/* * mbuf.c * * Written by Toshiharu OHNO * Copyright (c) 1993, Internet Initiative Japan, Inc. All rights reserved. * See ``COPYRIGHT.iij'' * * Rewritten by Archie Cobbs * Copyright (c) 1995-1999 Whistle Communications, Inc. All rights reserved. * See ``COPYRIGHT.whistle'' */ #include "ppp.h" /* * DEFINITIONS */ #define MBUF_CHECK_OVERRUNS #define MBUF_MAGIC_1 0x99999999 #define MBUF_MAGIC_2 0xaaaaaaaa struct typestat { const short type; const char *name; int count; }; /* * INTERNAL VARIABLES */ static int total_alloced; /* This list must correspond exactly with array in mbuf.h */ static struct typestat gMbufStats[] = { { MB_FSM, "FSM" }, { MB_PHYS, "PHYS" }, { MB_FRAME_IN, "FRAME_IN" }, { MB_FRAME_OUT, "FRAME_OUT" }, { MB_BUND, "BUND" }, { MB_ECHO, "ECHO" }, { MB_VJCOMP, "VJCOMP" }, { MB_LOG, "LOG" }, { MB_IPQ, "IPQ" }, { MB_MP, "MP" }, { MB_AUTH, "AUTH" }, { MB_UTIL, "UTIL" }, { MB_CHAT, "CHAT" }, { MB_COMP, "COMP" }, { MB_CRYPT, "CRYPT" }, { MB_PPTP, "PPTP" }, { MB_RADIUS, "RADIUS" }, }; #define NUM_TYPE_STATS (sizeof(gMbufStats) / sizeof(*gMbufStats)) /* * INTERNAL FUNCTIONS */ static void MbufTypeCount(int type, int change); /* * Malloc() * * Replacement for the ususal malloc() */ void * Malloc(int type, int size) { Mbuf bp; bp = mballoc(type, size + sizeof(Mbuf)); memcpy(MBDATA(bp), &bp, sizeof(bp)); return(MBDATA(bp) + sizeof(Mbuf)); } /* * Freee() * * Replacement for the ususal free() */ void Freee(const void *ptr) { Mbuf bp; if (ptr == NULL) return; bp = *((Mbuf *) ptr - 1); PFREE(bp); } /* * Asprintf() */ char * Asprintf(int type, const char *format, ...) { char *s; va_list args; va_start(args, format); vasprintf(&s, format, args); va_end(args); if (s == NULL) { Perror("%s", __FUNCTION__); DoExit(EX_ERRDEAD); } return strcpy(Malloc(type, strlen(s) + 1), s); } /* * mballoc() * * Allocate an mbuf with memory */ Mbuf mballoc(int type, int size) { u_char *memory; u_long amount; Mbuf bp; /* Sanity */ assert(size < ((1 << ((sizeof(short) * 8) - 1)) - 1)); /* Get memory */ #ifdef MBUF_CHECK_OVERRUNS amount = sizeof(*bp) + size + (2 * sizeof(u_int32_t)); #else amount = sizeof(*bp) + size; #endif if ((memory = malloc(amount)) == NULL) { Perror("mballoc: malloc"); DoExit(EX_ERRDEAD); } memset(memory, 0, amount); /* Put mbuf at front of memory region */ bp = (Mbuf)(void *)memory; bp->size = bp->cnt = size; bp->type = type; #ifdef MBUF_CHECK_OVERRUNS bp->base = memory + sizeof(*bp) + sizeof(u_int32_t); #else bp->base = memory + sizeof(*bp); #endif /* Straddle buffer with magic values to detect overruns */ #ifdef MBUF_CHECK_OVERRUNS *((u_int32_t *)(void *)(memory + sizeof(*bp))) = MBUF_MAGIC_1; *((u_int32_t *)(void *)(memory + sizeof(*bp) + sizeof(u_int32_t) + size)) = MBUF_MAGIC_2; #endif /* Keep tabs on who's got how much memory */ MbufTypeCount(bp->type, bp->size); /* Done */ return(bp); } /* * mbfree() * * Free head of chain, return next */ Mbuf mbfree(Mbuf bp) { Mbuf next; if (bp) { /* Sanity checks */ assert(bp->base); #ifdef MBUF_CHECK_OVERRUNS assert(bp == (Mbuf)(void *)(bp->base - sizeof(u_int32_t) - sizeof(*bp))); #else assert(bp == (Mbuf)(void *)(bp->base - sizeof(*bp))); #endif #ifdef MBUF_CHECK_OVERRUNS assert(*((u_int32_t *)(void *)(bp->base - sizeof(u_int32_t))) == MBUF_MAGIC_1); assert(*((u_int32_t *)(void *)(bp->base + bp->size)) == MBUF_MAGIC_2); #endif /* Keep tabs on who's got how much memory */ MbufTypeCount(bp->type, -bp->size); /* Free it */ next = bp->next; bp->base = NULL; free(bp); return(next); } return(NULL); } /* * mbread() * * Read contents of an mbuf chain into buffer, consuming len bytes. * If all of the chain is consumed, return NULL. * * This should ALWAYS be called like this: * bp = mbread(bp, ... ); */ Mbuf mbread(Mbuf bp, u_char *buf, int remain, int *nreadp) { int nread, total; for (total = 0; bp && remain > 0; total += nread) { if (remain > bp->cnt) nread = bp->cnt; else nread = remain; memcpy(buf, MBDATA(bp), nread); buf += nread; remain -= nread; bp->offset += nread; bp->cnt -= nread; while (bp != NULL && bp->cnt == 0) bp = mbfree(bp); } if (nreadp != NULL) *nreadp = total; return(bp); } /* * mbcopy() * * Copy contents of an mbuf chain into buffer, up to "remain" bytes. * This does not consume any of the mbuf chain. Returns number copied. */ int mbcopy(Mbuf bp, u_char *buf, int remain) { int nread, total; for (total = 0; bp && remain > 0; total += nread, bp = bp->next) { if (remain > bp->cnt) nread = bp->cnt; else nread = remain; memcpy(buf, MBDATA(bp), nread); buf += nread; remain -= nread; } return(total); } /* * mbwrite() * * Write bytes from buffer into an mbuf chain. Returns first argument. */ Mbuf mbwrite(Mbuf bp, const u_char *buf, int len) { Mbuf wp; int chunk; for (wp = bp; wp && len > 0; wp = wp->next) { chunk = (len > wp->cnt) ? wp->cnt : len; memcpy(MBDATA(wp), buf, chunk); buf += chunk; len -= chunk; } return(bp); } /* * mbtrunc() * * Truncate mbuf chain to total of "max" bytes. If max is zero * then a zero length mbuf is returned (rather than a NULL mbuf). */ Mbuf mbtrunc(Mbuf bp, int max) { Mbuf wp; int sum; /* Find mbuf in chain where truncation point happens */ for (sum = 0, wp = bp; wp && sum + wp->cnt <= max; sum += wp->cnt, wp = wp->next); /* Shorten this mbuf and nuke others after this one */ if (wp) { wp->cnt = max - sum; PFREE(wp->next); } /* Done */ return(bp); } /* * mbunify() * * Collect all of a chain into a single mbuf * * This should ALWAYS be called like this: * bp = mbunify(bp); */ Mbuf mbunify(Mbuf bp) { Mbuf new; int len; if (!bp || !bp->next) return(bp); new = mballoc(bp->type, len = plength(bp)); assert(mbread(bp, MBDATA(new), len, NULL) == NULL); return(new); } /* * mbclean() * * Remove zero (and negative!?) length mbufs from a chain */ Mbuf mbclean(Mbuf bp) { Mbuf *pp; pp = &bp; while (*pp) if ((*pp)->cnt <= 0) *pp = mbfree(*pp); else pp = &(*pp)->next; return(bp); } /* * mbsplit() * * Break an mbuf chain after "cnt" bytes. * Return the newly created mbuf chain that * starts after "cnt" bytes. If plength(bp) <= cnt, * then returns NULL. The first part of * the chain remains pointed to by "bp". */ Mbuf mbsplit(Mbuf bp, int cnt) { int seen, extra, tail; Mbuf mextra, next; /* Find mbuf in chain containing the breakpoint */ for (seen = 0; bp && seen + bp->cnt < cnt; seen += bp->cnt, bp = bp->next); if (bp == NULL) return(NULL); /* "tail" is how much stays in first part, "extra" goes into second part */ tail = cnt - seen; extra = bp->cnt - tail; /* Split in the middle of "bp" if necessary, creating "mextra" */ if (extra > 0) { mextra = mballoc(bp->type, extra); memcpy(MBDATA(mextra), MBDATA(bp) + tail, extra); bp->cnt = tail; mextra->next = bp->next; bp->next = mextra; } /* Now break point is just after "bp", so break the chain there */ next = bp->next; bp->next = NULL; return(next); } /* * MbufTypeCount() */ static void MbufTypeCount(int type, int change) { int index; /* Find structure for this type */ for (index = 0; index < NUM_TYPE_STATS && gMbufStats[index].type != type; index++); assert(index < NUM_TYPE_STATS); /* Update counters */ gMbufStats[index].count += change; total_alloced += change; assert(total_alloced >= 0); } /* * MemStat() */ int MemStat(int ac, char *av[], void *arg) { int index; for (index = 0; index < NUM_TYPE_STATS; index++) printf("%12s: %8d%c", gMbufStats[index].name, gMbufStats[index].count, (index & 1) ? '\n' : ' '); if (index & 1) printf("\n"); printf("Total bytes allocated: %d\n", total_alloced); return(0); }