home *** CD-ROM | disk | FTP | other *** search
- /* Primitive mbuf allocate/free routines */
-
- #include <stdlib.h>
- #include <string.h>
- #include "global.h"
- #include "mbuf.h"
-
- struct mbuf *ready_mbuf = NULL;
-
- /* Allocate mbuf with associated buffer of 'size' bytes */
- struct mbuf *alloc_mbuf(register int size)
- {
- register struct mbuf *bp, *lbp = NULL;
-
- if (size > 0 && ready_mbuf != NULL)
- {
- for (bp = ready_mbuf; bp != NULL; lbp = bp, bp = bp->next)
- {
- if (bp->size >= size)
- {
- if (lbp == NULL)
- ready_mbuf = bp->next;
- else
- lbp->next = bp->next;
- bp->next = bp->anext = NULLBUF;
- bp->cnt = 0;
- return(bp);
- }
- }
- }
-
- if ((bp = (struct mbuf *)malloc((unsigned)(size + sizeof(struct mbuf)))) == NULLBUF)
- return NULLBUF;
- bp->next = bp->anext = NULLBUF;
- if (size != 0)
- {
- bp->data = (char *)(bp + 1);
- }
- else
- {
- bp->data = NULLCHAR;
- }
- bp->size = size;
- bp->cnt = 0;
- return bp;
- }
-
- /* Free all resources associated with mbuf
- Return pointer to next mbuf in packet chain */
- struct mbuf *free_mbuf(register struct mbuf *bp)
- {
- register struct mbuf *bp1 = NULLBUF;
-
- if (bp != NULLBUF)
- {
- bp1 = bp->next;
- if (bp->size > 0 && bp->data >= (char *)(bp + 1) && bp->data <= ((char *) bp) + bp->size + sizeof(struct mbuf))
- {
- bp->data = (char *)(bp + 1);
- bp->next = ready_mbuf;
- bp->anext = NULLBUF;
- ready_mbuf = bp;
- }
- else
- {
- free((char *)bp);
- }
- }
- return bp1;
- }
-
- /* Free packet (a chain of mbufs). Return pointer to next packet on queue,
- if any */
- struct mbuf *free_p(register struct mbuf *bp)
- {
- struct mbuf *abp;
-
- if(bp == NULLBUF)
- return NULLBUF;
- abp = bp->anext;
- while(bp != NULLBUF)
- bp = free_mbuf(bp);
- return abp;
- }
- /* Free entire queue of packets (of mbufs) */
- void free_q(struct mbuf **q)
- {
- register struct mbuf *bp;
-
- while((bp = dequeue(q)) != NULLBUF)
- free_p(bp);
- }
-
- /* Count up the total number of bytes in an mbuf */
- int len_mbuf(register struct mbuf *bp)
- {
- int cnt;
-
- cnt = 0;
- while(bp != NULLBUF)
- {
- cnt += bp->cnt;
- bp = bp->next;
- }
- return cnt;
- }
- /* Count up the number of packets in a queue */
- int len_q(register struct mbuf *bp)
- {
- register int cnt;
-
- for (cnt = 0;bp != NULLBUF; cnt++, bp = bp->anext)
- ;
- return cnt;
- }
- /* Trim mbuf to specified length by lopping off end */
- void trim_mbuf(struct mbuf **bpp, int length)
- {
- register int tot = 0;
- register struct mbuf *bp;
-
- if(bpp == NULLBUFP || *bpp == NULLBUF)
- return; /* Nothing to trim */
-
- if(length == 0)
- {
- /* Toss the whole thing */
- free_p(*bpp);
- *bpp = NULLBUF;
- return;
- }
- /* Find the point at which to trim. If length is greater than
- * the packet, we'll just fall through without doing anything
- */
- for( bp = *bpp; bp != NULLBUF; bp = bp->next)
- {
- if(tot + bp->cnt < length)
- {
- tot += bp->cnt;
- }
- else
- {
- /* Cut here */
- bp->cnt = length - tot;
- free_p(bp->next);
- bp->next = NULLBUF;
- break;
- }
- }
- }
- /* Duplicate/enqueue/dequeue operations based on mbufs */
-
- /* Duplicate first 'cnt' bytes of packet starting at 'offset'.
- * This is done without copying data; only the headers are duplicated,
- * but without data segments of their own. The pointers are set up to
- * share the data segments of the original copy. The return pointer is
- * passed back through the first argument, and the return value is the
- * number of bytes actually duplicated.
- */
- int dup_p(struct mbuf **hp, register struct mbuf *bp,
- register int offset, register int cnt)
- {
- register struct mbuf *cp;
- int tot;
-
- if(cnt == 0 || bp == NULLBUF || hp == NULLBUFP){
- if(hp != NULLBUFP)
- *hp = NULLBUF;
- return 0;
- }
- if((*hp = cp = alloc_mbuf(0)) == NULLBUF)
- {
- return 0;
- }
- /* Skip over leading mbufs that are smaller than the offset */
- while(bp != NULLBUF && bp->cnt <= offset)
- {
- offset -= bp->cnt;
- bp = bp->next;
- }
- if (bp == NULLBUF)
- {
- free_mbuf(cp);
- *hp = NULLBUF;
- return 0; /* Offset was too big */
- }
- tot = 0;
- for(;;)
- {
- cp->data = bp->data + offset;
- cp->cnt = min(cnt,bp->cnt - offset);
- offset = 0;
- cnt -= cp->cnt;
- tot += cp->cnt;
- bp = bp->next;
- if(cnt == 0 || bp == NULLBUF || (cp->next = alloc_mbuf(0)) == NULLBUF)
- break;
- cp = cp->next;
- }
- return tot;
- }
- /* Copy first 'cnt' bytes of packet into a new, single mbuf */
- struct mbuf *copy_p(register struct mbuf *bp, register int cnt)
- {
- register struct mbuf *cp;
- register char *wp;
- register int n;
-
- if(bp == NULLBUF || cnt == 0 || (cp = alloc_mbuf(cnt)) == NULLBUF)
- return NULLBUF;
- wp = cp->data;
- while(cnt != 0 && bp != NULLBUF)
- {
- n = min(cnt, bp->cnt);
- memcpy(wp, bp->data, n);
- wp += n;
- cp->cnt += n;
- cnt -= n;
- bp = bp->next;
- }
- return cp;
- }
-
- int pullone(struct mbuf **bph, char *buf)
- {
- register struct mbuf *bp;
-
- if (bph == NULL || *bph == NULL)
- return(0);
-
- bp = *bph;
- *buf = *bp->data;
- (bp->data)++;
-
- if (--(bp->cnt) == 0)
- {
- if (bp->next == NULL && bp->anext != NULL)
- {
- *bph = bp->anext;
- free_mbuf(bp);
- }
- else
- {
- *bph = free_mbuf(bp);
- }
- }
- return(1);
- }
-
- /* Copy and delete "cnt" bytes from beginning of packet. Return number of
- bytes actually pulled off */
- int pullup(struct mbuf **bph, char *buf, int cnt)
- {
- register struct mbuf *bp;
- int n, tot = 0;
-
- if (bph == NULL)
- return 0;
- while (*bph != NULL && cnt != 0)
- {
- bp = *bph;
- n = min(cnt, bp->cnt);
- if (buf != NULL && n != 0)
- {
- if (n == 1) /* Common case optimization */
- *buf = *bp->data;
- else if(n > 1)
- memcpy(buf, bp->data, n);
- buf += n;
- }
- tot += n;
- cnt -= n;
- bp->data += n;
- bp->cnt -= n;
- if (bp->cnt == 0)
- {
- /* If this is the last mbuf of a packet but there
- * are others on the queue, return a pointer to
- * the next on the queue. This allows pullups to
- * to work on a packet queue
- */
- if (bp->next == NULL && bp->anext != NULL)
- {
- *bph = bp->anext;
- free_mbuf(bp);
- }
- else
- {
- *bph = free_mbuf(bp);
- }
- }
- }
- return tot;
- }
- /* Append mbuf to end of mbuf chain */
- void append(struct mbuf **bph, struct mbuf *bp)
- {
- register struct mbuf *p;
-
- if(bph == NULLBUFP || bp == NULLBUF)
- return;
- if(*bph == NULLBUF){
- /* First one on chain */
- *bph = bp;
- }
- else
- {
- for(p = *bph ; p->next != NULLBUF ; p = p->next)
- ;
- p->next = bp;
- }
- }
- /* Insert specified amount of contiguous new space at the beginning of an
- * mbuf chain. If enough space is available in the first mbuf, no new space
- * is allocated. Otherwise a mbuf of the appropriate size is allocated and
- * tacked on the front of the chain.
- *
- * This operation is the logical inverse of pullup(), hence the name.
- */
- struct mbuf *pushdown(register struct mbuf *bp, int size)
- {
- register struct mbuf *nbp;
-
- /* Check that bp is real and that there's data space associated with
- * this buffer (i.e., this is not a buffer from dup_p) before
- * checking to see if there's enough space at its front
- */
- if(bp != NULLBUF && bp->size != 0 && bp->data - (char *)(bp+1) >= size)
- {
- /* No need to alloc new mbuf, just adjust this one */
- bp->data -= size;
- bp->cnt += size;
- }
- else
- {
- if ((nbp = alloc_mbuf(size)) != NULLBUF)
- {
- nbp->next = bp;
- nbp->cnt = size;
- bp = nbp;
- }
- else
- {
- bp = NULLBUF;
- }
- }
- return bp;
- }
- /* Append packet to end of packet queue */
- void enqueue(struct mbuf **q, struct mbuf *bp)
- {
- register struct mbuf *p;
-
- if(q == NULLBUFP || bp == NULLBUF)
- return;
- if(*q == NULLBUF){
- /* List is empty, stick at front */
- *q = bp;
- } else {
- for(p = *q ; p->anext != NULLBUF ; p = p->anext)
- ;
- p->anext = bp;
- }
- }
- /* Unlink a packet from the head of the queue */
- struct mbuf *dequeue(register struct mbuf **q)
- {
- register struct mbuf *bp;
-
- if(q == NULLBUFP)
- return NULLBUF;
- if((bp = *q) != NULLBUF){
- *q = bp->anext;
- bp->anext = NULLBUF;
- }
- return bp;
- }
-
- /* Copy user data into an mbuf */
- struct mbuf *qdata(char *data, int cnt)
- {
- register struct mbuf *bp;
-
- if((bp = alloc_mbuf(cnt)) == NULLBUF)
- return NULLBUF;
- memcpy(bp->data, data, cnt);
- bp->cnt = cnt;
- return bp;
- }
- /* Copy mbuf data into user buffer */
- int dqdata(struct mbuf *bp, char *buf, unsigned cnt)
- {
- unsigned n,tot;
- struct mbuf *bp1;
-
- if(buf == NULLCHAR)
- return 0;
-
- tot = 0;
- for(bp1 = bp;bp1 != NULLBUF; bp1 = bp1->next){
- n = min(bp1->cnt,cnt);
- memcpy(buf,bp1->data,n);
- cnt -= n;
- buf += n;
- tot += n;
- }
- free_p(bp);
- return tot;
- }
- /* Pull a 32-bit integer in host order from buffer in network byte order */
- int32 pull32(struct mbuf **bpp)
- {
- int32 rval;
- char buf[4];
- register char *cp;
-
- if (pullup(bpp, buf, 4) != 4)
- {
- /* Return zero if insufficient buffer */
- return 0;
- }
- cp = buf;
-
- /* Unwound for speed */
- rval = uchar(*cp++);
- rval <<= 8;
- rval |= uchar(*cp++);
- rval <<= 8;
- rval |= uchar(*cp++);
- rval <<= 8;
- rval |= uchar(*cp);
-
- return rval;
- }
- /* Pull a 16-bit integer in host order from buffer in network byte order */
- int pull16(struct mbuf **bpp)
- {
- int rval;
- char buf[2];
- register char *cp;
-
- if (pullup(bpp, buf, 2) != 2)
- {
- /* Return zero if insufficient buffer */
- return 0;
- }
- cp = buf;
-
- rval = *cp++;
- rval <<= 8;
- rval |= *cp;
- return rval;
- }
- /* Pull single character from mbuf */
- char pullchar(struct mbuf **bpp)
- {
- char c;
-
- if (pullone(bpp, &c) != 1)
- /* Return zero if nothing left */
- c = 0;
- return c;
- }
-
-