/* Primitive mbuf allocate/free routines */ #ifdef TRACE #include #endif #include "machdep.h" #include "mbuf.h" /* Allocate mbuf with associated buffer of 'size' bytes */ struct mbuf * alloc_mbuf(size) register int16 size; { register struct mbuf *bp; char *malloc(); 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->cnt = 0; return bp; } /* Free all resources associated with mbuf * Return pointer to next mbuf in packet chain */ struct mbuf * free_mbuf(bp) register struct mbuf *bp; { register struct mbuf *bp1 = NULLBUF; if(bp != NULLBUF){ bp1 = bp->next; free((char *)bp); } return bp1; } /* Free packet (a chain of mbufs). Return pointer to next packet on queue, * if any */ struct mbuf * free_p(bp) 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) */ free_q(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 */ int16 len_mbuf(bp) 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 */ int16 len_q(bp) register struct mbuf *bp; { register int cnt; for(cnt=0;bp != NULLBUF;cnt++,bp = bp->anext) ; return cnt; } /* 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. */ int16 dup_p(hp,bp,offset,cnt) struct mbuf **hp; register struct mbuf *bp; register int16 offset; register int16 cnt; { register struct mbuf *cp; int16 tot; if(cnt == 0 || bp == NULLBUF || hp == (struct mbuf **)NULL){ if(hp != (struct mbuf **)NULL) *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(bp,cnt) register struct mbuf *bp; register int16 cnt; { register struct mbuf *cp; register char *wp; register int16 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); bcopy(bp->data,wp,n); wp += n; cp->cnt += n; cnt -= n; bp = bp->next; } return cp; } /* Copy and delete "cnt" bytes from beginning of packet. Return number of * bytes actually pulled off */ int16 pullup(bph,buf,cnt) struct mbuf **bph; char *buf; int16 cnt; { register struct mbuf *bp; int16 n,tot; tot = 0; if(bph == (struct mbuf **)NULL) return 0; while(*bph != NULLBUF && cnt != 0){ bp = *bph; n = min(cnt,bp->cnt); if(buf != NULLCHAR){ bcopy(bp->data,buf,n); buf += n; } tot += n; cnt -= n; bp->data += n; bp->cnt -= n; if(bp->cnt == 0){ *bph = free_mbuf(bp); } } return tot; } /* Append mbuf to end of mbuf chain */ int16 append(bph,bp) struct mbuf **bph; struct mbuf *bp; { register struct mbuf *p; if(bph == (struct mbuf **)NULL || 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; } } /* Append packet to end of packet queue */ void enqueue(q,bp) struct mbuf **q; struct mbuf *bp; { register struct mbuf *p; char i_state; if(q == (struct mbuf **)NULL || bp == NULLBUF) return; i_state = disable(); if(*q == NULLBUF){ /* List is empty, stick at front */ *q = bp; } else { for(p = *q ; p->anext != NULLBUF ; p = p->anext) ; p->anext = bp; } restore(i_state); } /* Unlink a packet from the head of the queue */ struct mbuf * dequeue(q) register struct mbuf **q; { register struct mbuf *bp; char i_state; if(q == (struct mbuf **)NULL) return NULLBUF; i_state = disable(); if((bp = *q) != NULLBUF){ *q = bp->anext; bp->anext = NULLBUF; } restore(i_state); return bp; } /* Copy user data into an mbuf */ struct mbuf * qdata(data,cnt) char *data; int16 cnt; { register struct mbuf *bp; if((bp = alloc_mbuf(cnt)) == NULLBUF) return NULLBUF; bcopy(data,bp->data,cnt); bp->cnt = cnt; return bp; } /* Copy mbuf data into user buffer */ int16 dqdata(bp,buf,cnt) 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); bcopy(bp1->data,buf,n); cnt -= n; buf += n; tot += n; } free_p(bp); return tot; } #ifdef TRACE /* Comment this out if your library already has this function */ #define isprint(c) ((c) >= ' ' && (c) < 0x7f) /* Assumes ASCII */ /* Dump an mbuf in hex */ void hexdump(bp) struct mbuf *bp; { register struct mbuf *tbp; int16 n; int16 address; void fmtline(); if(bp == NULLBUF) return; tbp = copy_p(bp,len_mbuf(bp)); address = 0; while(tbp->cnt != 0){ n = min(tbp->cnt,16); fmtline(address,tbp->data,n); address += n; tbp->data += n; tbp->cnt -= n; } free_p(tbp); fflush(stdout); } /* Dump an mbuf in ascii */ void asciidump(bp) struct mbuf *bp; { struct mbuf *tbp; char c; int16 tot; if(bp == NULLBUF) return; tbp = copy_p(bp,len_mbuf(bp)); tot = 0; while(pullup(&tbp,&c,1) == 1){ if((tot % 64) == 0) printf("%04x ",tot); if(isprint(c)) putchar(c); else putchar('.'); tot++; if((tot % 64) == 0) printf("\r\n"); } if((tot % 64) != 0) printf("\r\n"); free_p(tbp); fflush(stdout); } /* Print a buffer up to 16 bytes long in formatted hex with ascii * translation, e.g., * 0000: 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 0123456789:;<=>? */ void fmtline(addr,buf,len) int16 addr; char *buf; int16 len; { char line[80]; char *aptr,*cptr; int16 c; void ctohex(); for(cptr = line;cptr < &line[80];cptr++) *cptr = ' '; ctohex(line,(int16)hibyte(addr)); ctohex(line+2,(int16)lobyte(addr)); aptr = &line[6]; cptr = &line[55]; while(len-- != 0){ c = *buf++ & 0xff; ctohex(aptr,c); aptr += 3; c &= 0x7f; if(isprint(c)){ *cptr++ = c; } else { *cptr++ = '.'; } } *cptr++ = '\r'; *cptr++ = '\n'; #ifdef AMIGA *cptr = '\0'; printf(line); #else fwrite(line,1,(unsigned)(cptr-line),stdout); #endif } /* Convert byte to two ascii-hex characters */ static void ctohex(buf,c) char *buf; int16 c; { static char hex[] = "0123456789abcdef"; buf[0] = hex[hinibble(c)]; buf[1] = hex[lonibble(c)]; } #endif