home *** CD-ROM | disk | FTP | other *** search
/ The Pier Shareware 6 / The_Pier_Shareware_Number_6_(The_Pier_Exchange)_(1995).iso / 024 / psi110g.zip / MBUF.C < prev    next >
C/C++ Source or Header  |  1994-04-17  |  18KB  |  638 lines

  1. /* mbuf (message buffer) primitives
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  *
  4.  * Mods by G1EMM
  5.  */
  6.   
  7. #ifdef MSDOS
  8. #include <dos.h>        /* TEMP */
  9. #endif
  10. #include "global.h"
  11. #ifdef MSDOS
  12. #include <alloc.h>
  13. #endif
  14. #include "mbuf.h"
  15. #include "proc.h"
  16. #include "config.h"
  17.   
  18. #ifndef LINUX
  19.   
  20. /* Interrupt buffer pool */
  21. int Intqlen;                    /* Number of free mbufs on Intq */
  22. struct mbuf *Intq;              /* Mbuf pool for interrupt handlers */
  23. struct mbuf *Garbq;             /* List of buffers freed at interrupt time */
  24. long Ibuffail;                  /* Allocate failures */
  25. int Iminfree  = -1;             /* minimum free buffers */
  26.   
  27. void
  28. refiq()
  29. {
  30.     register struct mbuf *bp;
  31.     char i_state;
  32. #ifdef  PI              /* Temp hack to satisfy PI DMA requirements */
  33.     int32 dma_abs;  /* TEMP */
  34.     int16 dma_page; /* TEMP */
  35. #endif
  36.   
  37.     /* Empty the garbage */
  38.     if(Garbq != NULLBUF){
  39.         i_state = dirps();
  40.         bp = Garbq;
  41.         Garbq = NULLBUF;
  42.         restore(i_state);
  43.         free_p(bp);
  44.     }
  45.     /* Replenish interrupt buffer pool */ /* G1EMM and HB9RWM fix */
  46.     while((Intqlen < Nibufs) && (Memthresh < availmem()) ){
  47. #ifdef notdef
  48.         while(Intqlen < Nibufs){
  49. #endif
  50.             if((bp = alloc_mbuf(Ibufsize)) == NULLBUF)
  51.                 break;
  52. #ifdef  PI              /* Temp hack to satisfy PI DMA requirements */
  53.             dma_abs = ((long)FP_SEG(bp->data) << 4) + (long)FP_OFF(bp->data);
  54.             dma_page = dma_abs >> 16;
  55.             if(((dma_abs+Ibufsize) >> 16) != dma_page){
  56.                 i_state = dirps();
  57.                 bp->next = Garbq;
  58.                 Garbq = bp;
  59.                 restore(i_state);
  60.                 continue;
  61.             }
  62. #endif
  63.   
  64.             i_state = dirps();
  65.             bp->next = Intq;
  66.             Intq = bp;
  67.             Intqlen++;
  68.             restore(i_state);
  69.         }
  70.         if(Iminfree == -1)
  71.             Iminfree = Intqlen;
  72.     }
  73.   
  74.     void
  75.     iqstat()
  76.     {
  77.         tprintf("Intqlen %u Ibufsize %u Iminfree %u Ibuffail %lu\n",
  78.         Intqlen,Ibufsize,Iminfree,Ibuffail);
  79.     }
  80.   
  81.     void
  82.     iqclear()
  83.     {
  84.         Ibuffail = 0;
  85.         Iminfree = -1;
  86.     }
  87. #endif /* LINUX */
  88.   
  89. /* Allocate mbuf with associated buffer of 'size' bytes. If interrupts
  90.  * are enabled, use the regular heap. If they're off, use the special
  91.  * interrupt buffer pool.
  92.  */
  93.     struct mbuf *
  94.     alloc_mbuf(size)
  95.     register int16 size;
  96.     {
  97.         register struct mbuf *bp;
  98.   
  99. #ifndef LINUX
  100.         if(istate()){
  101. #endif
  102.         /* Interrupts are enabled, use the heap normally */
  103.             bp = (struct mbuf *)malloc((unsigned)(size + sizeof(struct mbuf)));
  104.             if(bp == NULLBUF)
  105.                 return NULLBUF;
  106.         /* Clear just the header portion */
  107.             memset((char *)bp,0,sizeof(struct mbuf));
  108.             if((bp->size = size) != 0)
  109.                 bp->data = (char *)(bp + 1);
  110.             bp->refcnt++;
  111. #ifndef LINUX
  112.         } else {
  113.         /* Interrupts are off, use special interrupt buffer pool */
  114.             if(size > Ibufsize || Intq == NULLBUF){
  115.                 Ibuffail++;
  116.                 return NULLBUF;
  117.             }
  118.             bp = Intq;
  119.             Intq = bp->next;
  120.             bp->next = NULLBUF;
  121.             Intqlen--;
  122.         }
  123.         if(Intqlen < Iminfree)
  124.             Iminfree = Intqlen;
  125. #endif /* LINUX */
  126.         return bp;
  127.     }
  128. /* Allocate mbuf, waiting if memory is unavailable */
  129.     struct mbuf *
  130.     ambufw(size)
  131.     int16 size;
  132.     {
  133.         register struct mbuf *bp;
  134.   
  135.         bp = (struct mbuf *)mallocw((unsigned)(size + sizeof(struct mbuf)));
  136.   
  137.     /* Clear just the header portion */
  138.         memset((char *)bp,0,sizeof(struct mbuf));
  139.         if((bp->size = size) != 0)
  140.             bp->data = (char *)(bp + 1);
  141.         bp->refcnt++;
  142.         return bp;
  143.     }
  144.   
  145. /* Decrement the reference pointer in an mbuf. If it goes to zero,
  146.  * free all resources associated with mbuf.
  147.  * Return pointer to next mbuf in packet chain
  148.  */
  149.     struct mbuf *
  150.     free_mbuf(bp)
  151.     register struct mbuf *bp;
  152.     {
  153.         struct mbuf *bpnext;
  154.         struct mbuf *bptmp;
  155.   
  156.         if(bp == NULLBUF)
  157.             return NULLBUF;
  158.   
  159.         bpnext = bp->next;
  160.         if(bp->dup != NULLBUF){
  161.             bptmp = bp->dup;
  162.             bp->dup = NULLBUF;  /* Nail it before we recurse */
  163.             free_mbuf(bptmp);   /* Follow indirection */
  164.         }
  165.     /* Decrement reference count. If it has gone to zero, free it. */
  166.         if(--bp->refcnt <= 0){
  167.         /* If interrupts are on, simply free the buffer.
  168.          * Otherwise put it on the garbage list where it
  169.          * will be freed by refiq() later with interrupts
  170.          * enabled.
  171.          */
  172. #ifndef LINUX
  173.             if(istate()){
  174. #endif
  175.                 free((char *)bp);
  176. #ifndef LINUX
  177.             } else {
  178.                 bp->refcnt = 1; /* Adjust */
  179.             /* free ibufsize buffers to the interrupt q, if not full. */
  180.                 if(bp->size == Ibufsize && Intqlen < Nibufs) {
  181.                     bp->next = Intq;
  182.                     bp->anext = NULLBUF;
  183.                     bp->data = (char *)(bp + 1);
  184.                     bp->cnt = 0;
  185.                     Intq = bp;
  186.                     Intqlen++;
  187.                 } else {
  188.             /* put on garbage queue */
  189.                     bp->next = Garbq;
  190.                     Garbq = bp;
  191.                 }
  192.             }
  193. #endif /* LINUX */
  194.         }
  195.         return bpnext;
  196.     }
  197.   
  198. /* Free packet (a chain of mbufs). Return pointer to next packet on queue,
  199.  * if any
  200.  */
  201.     struct mbuf *
  202.     free_p(bp)
  203.     register struct mbuf *bp;
  204.     {
  205.         struct mbuf *abp;
  206.   
  207.         if(bp == NULLBUF)
  208.             return NULLBUF;
  209.         abp = bp->anext;
  210.         while(bp != NULLBUF)
  211.             bp = free_mbuf(bp);
  212.         return abp;
  213.     }
  214.   
  215. /* Free entire queue of packets (of mbufs) */
  216.     void
  217.     free_q(q)
  218.     struct mbuf **q;
  219.     {
  220.         register struct mbuf *bp;
  221.   
  222.         while((bp = dequeue(q)) != NULLBUF)
  223.             free_p(bp);
  224.     }
  225.   
  226. /* Count up the total number of bytes in a packet */
  227.     int16
  228.     len_p(bp)
  229.     register struct mbuf *bp;
  230.     {
  231.         register int16 cnt = 0;
  232.   
  233.         while(bp != NULLBUF){
  234.             cnt += bp->cnt;
  235.             bp = bp->next;
  236.         }
  237.         return cnt;
  238.     }
  239.   
  240. /* Count up the number of packets in a queue */
  241.     int16
  242.     len_q(bp)
  243.     register struct mbuf *bp;
  244.     {
  245.         register int16 cnt;
  246.   
  247.         for(cnt=0;bp != NULLBUF;cnt++,bp = bp->anext)
  248.             ;
  249.         return cnt;
  250.     }
  251.   
  252. /* Trim mbuf to specified length by lopping off end */
  253.     void
  254.     trim_mbuf(bpp,length)
  255.     struct mbuf **bpp;
  256.     int16 length;
  257.     {
  258.         register int16 tot = 0;
  259.         register struct mbuf *bp;
  260.   
  261.         if(bpp == NULLBUFP || *bpp == NULLBUF)
  262.             return; /* Nothing to trim */
  263.   
  264.         if(length == 0){
  265.         /* Toss the whole thing */
  266.             free_p(*bpp);
  267.             *bpp = NULLBUF;
  268.             return;
  269.         }
  270.     /* Find the point at which to trim. If length is greater than
  271.      * the packet, we'll just fall through without doing anything
  272.      */
  273.         for( bp = *bpp; bp != NULLBUF; bp = bp->next){
  274.             if(tot + bp->cnt < length){
  275.                 tot += bp->cnt;
  276.             } else {
  277.             /* Cut here */
  278.                 bp->cnt = length - tot;
  279.                 free_p(bp->next);
  280.                 bp->next = NULLBUF;
  281.                 break;
  282.             }
  283.         }
  284.     }
  285. /* Duplicate/enqueue/dequeue operations based on mbufs */
  286.   
  287. /* Duplicate first 'cnt' bytes of packet starting at 'offset'.
  288.  * This is done without copying data; only the headers are duplicated,
  289.  * but without data segments of their own. The pointers are set up to
  290.  * share the data segments of the original copy. The return pointer is
  291.  * passed back through the first argument, and the return value is the
  292.  * number of bytes actually duplicated.
  293.  */
  294.     int16
  295.     dup_p(hp,bp,offset,cnt)
  296.     struct mbuf **hp;
  297.     register struct mbuf *bp;
  298.     register int16 offset;
  299.     register int16 cnt;
  300.     {
  301.         register struct mbuf *cp;
  302.         int16 tot;
  303.   
  304.         if(cnt == 0 || bp == NULLBUF || hp == NULLBUFP){
  305.             if(hp != NULLBUFP)
  306.                 *hp = NULLBUF;
  307.             return 0;
  308.         }
  309.         if((*hp = cp = alloc_mbuf(0)) == NULLBUF){
  310.             return 0;
  311.         }
  312.     /* Skip over leading mbufs that are smaller than the offset */
  313.         while(bp != NULLBUF && bp->cnt <= offset){
  314.             offset -= bp->cnt;
  315.             bp = bp->next;
  316.         }
  317.         if(bp == NULLBUF){
  318.             free_mbuf(cp);
  319.             *hp = NULLBUF;
  320.             return 0;       /* Offset was too big */
  321.         }
  322.         tot = 0;
  323.         for(;;){
  324.         /* Make sure we get the original, "real" buffer (i.e. handle the
  325.          * case of duping a dupe)
  326.          */
  327.             if(bp->dup != NULLBUF)
  328.                 cp->dup = bp->dup;
  329.             else
  330.                 cp->dup = bp;
  331.   
  332.         /* Increment the duplicated buffer's reference count */
  333.             cp->dup->refcnt++;
  334.   
  335.             cp->data = bp->data + offset;
  336.             cp->cnt = min(cnt,bp->cnt - offset);
  337.             offset = 0;
  338.             cnt -= cp->cnt;
  339.             tot += cp->cnt;
  340.             bp = bp->next;
  341.             if(cnt == 0 || bp == NULLBUF || (cp->next = alloc_mbuf(0)) == NULLBUF)
  342.                 break;
  343.             cp = cp->next;
  344.         }
  345.         return tot;
  346.     }
  347. /* Copy first 'cnt' bytes of packet into a new, single mbuf */
  348.     struct mbuf *
  349.     copy_p(bp,cnt)
  350.     register struct mbuf *bp;
  351.     register int16 cnt;
  352.     {
  353.         register struct mbuf *cp;
  354.         register char *wp;
  355.         register int16 n;
  356.   
  357.         if(bp == NULLBUF || cnt == 0 || (cp = alloc_mbuf(cnt)) == NULLBUF)
  358.             return NULLBUF;
  359.         wp = cp->data;
  360.         while(cnt != 0 && bp != NULLBUF){
  361.             n = min(cnt,bp->cnt);
  362.             memcpy(wp,bp->data,n);
  363.             wp += n;
  364.             cp->cnt += n;
  365.             cnt -= n;
  366.             bp = bp->next;
  367.         }
  368.         return cp;
  369.     }
  370. /* Copy and delete "cnt" bytes from beginning of packet. Return number of
  371.  * bytes actually pulled off
  372.  */
  373.     int16
  374.     pullup(bph,buf,cnt)
  375.     struct mbuf **bph;
  376.     char *buf;
  377.     int16 cnt;
  378.     {
  379.         register struct mbuf *bp;
  380.         int16 n,tot;
  381.   
  382.         tot = 0;
  383.         if(bph == NULLBUFP)
  384.             return 0;
  385.         while(cnt != 0 && (bp = *bph) != NULLBUF){
  386.             n = min(cnt,bp->cnt);
  387.             if(buf != NULLCHAR){
  388.                 if(n == 1)      /* Common case optimization */
  389.                     *buf = *bp->data;
  390.                 else if(n > 1)
  391.                     memcpy(buf,bp->data,n);
  392.                 buf += n;
  393.             }
  394.             tot += n;
  395.             cnt -= n;
  396.             bp->data += n;
  397.             bp->cnt -= n;
  398.             if(bp->cnt == 0){
  399.             /* If this is the last mbuf of a packet but there
  400.              * are others on the queue, return a pointer to
  401.              * the next on the queue. This allows pullups to
  402.              * to work on a packet queue
  403.              */
  404.                 if(bp->next == NULLBUF && bp->anext != NULLBUF){
  405.                     *bph = bp->anext;
  406.                     free_mbuf(bp);
  407.                 } else
  408.                     *bph = free_mbuf(bp);
  409.             }
  410.         }
  411.         return tot;
  412.     }
  413. /* Append mbuf to end of mbuf chain */
  414.     void
  415.     append(bph,bp)
  416.     struct mbuf **bph;
  417.     struct mbuf *bp;
  418.     {
  419.         register struct mbuf *p;
  420.         char i_state;
  421.   
  422.         if(bph == NULLBUFP || bp == NULLBUF)
  423.             return;
  424.   
  425.         i_state=dirps();
  426.         if(*bph == NULLBUF){
  427.         /* First one on chain */
  428.             *bph = bp;
  429.         } else {
  430.             for(p = *bph ; p->next != NULLBUF ; p = p->next)
  431.                 ;
  432.             p->next = bp;
  433.         }
  434.         restore(i_state);
  435.         psignal(bph,1);
  436.     }
  437. /* Insert specified amount of contiguous new space at the beginning of an
  438.  * mbuf chain. If enough space is available in the first mbuf, no new space
  439.  * is allocated. Otherwise a mbuf of the appropriate size is allocated and
  440.  * tacked on the front of the chain.
  441.  *
  442.  * This operation is the logical inverse of pullup(), hence the name.
  443.  */
  444.     struct mbuf *
  445.     pushdown(bp,size)
  446.     register struct mbuf *bp;
  447.     int16 size;
  448.     {
  449.         register struct mbuf *nbp;
  450.   
  451.     /* Check that bp is real, that it hasn't been duplicated, and
  452.      * that it itself isn't a duplicate before checking to see if
  453.      * there's enough space at its front.
  454.      */
  455.         if(bp != NULLBUF && bp->refcnt == 1 && bp->dup == NULLBUF
  456.         && bp->data - (char *)(bp+1) >= size){
  457.         /* No need to alloc new mbuf, just adjust this one */
  458.             bp->data -= size;
  459.             bp->cnt += size;
  460.         } else {
  461.             nbp = ambufw(size);
  462.             nbp->next = bp;
  463.             nbp->cnt = size;
  464.             bp = nbp;
  465.         }
  466.         return bp;
  467.     }
  468. /* Append packet to end of packet queue */
  469.     void
  470.     enqueue(q,bp)
  471.     struct mbuf **q;
  472.     struct mbuf *bp;
  473.     {
  474.         register struct mbuf *p;
  475.         char i_state;
  476.   
  477.         if(q == NULLBUFP || bp == NULLBUF)
  478.             return;
  479.         i_state = dirps();
  480.         if(*q == NULLBUF){
  481.         /* List is empty, stick at front */
  482.             *q = bp;
  483.         } else {
  484.             for(p = *q ; p->anext != NULLBUF ; p = p->anext)
  485.                 ;
  486.             p->anext = bp;
  487.         }
  488.         restore(i_state);
  489.         psignal(q,1);
  490.     }
  491. /* Unlink a packet from the head of the queue */
  492.     struct mbuf *
  493.     dequeue(q)
  494.     register struct mbuf **q;
  495.     {
  496.         register struct mbuf *bp;
  497.         char i_state;
  498.   
  499.         if(q == NULLBUFP)
  500.             return NULLBUF;
  501.         i_state = dirps();
  502.         if((bp = *q) != NULLBUF){
  503.             *q = bp->anext;
  504.             bp->anext = NULLBUF;
  505.         }
  506.         restore(i_state);
  507.         return bp;
  508.     }
  509.   
  510. /* Copy user data into an mbuf */
  511.     struct mbuf *
  512.     qdata(data,cnt)
  513.     char *data;
  514.     int16 cnt;
  515.     {
  516.         register struct mbuf *bp;
  517.   
  518.         bp = ambufw(cnt);
  519.         memcpy(bp->data,data,cnt);
  520.         bp->cnt = cnt;
  521.         return bp;
  522.     }
  523. /* Copy mbuf data into user buffer */
  524.     int16
  525.     dqdata(bp,buf,cnt)
  526.     struct mbuf *bp;
  527.     char *buf;
  528.     unsigned cnt;
  529.     {
  530.         int16 tot;
  531.         unsigned n;
  532.         struct mbuf *bp1;
  533.   
  534.         if(buf == NULLCHAR)
  535.             return 0;
  536.   
  537.         tot = 0;
  538.         for(bp1 = bp;bp1 != NULLBUF; bp1 = bp1->next){
  539.             n = min(bp1->cnt,cnt);
  540.             memcpy(buf,bp1->data,n);
  541.             cnt -= n;
  542.             buf += n;
  543.             tot += n;
  544.         }
  545.         free_p(bp);
  546.         return tot;
  547.     }
  548. /* Pull a 32-bit integer in host order from buffer in network byte order.
  549.  * On error, return 0. Note that this is indistinguishable from a normal
  550.  * return.
  551.  */
  552.     int32
  553.     pull32(bpp)
  554.     struct mbuf **bpp;
  555.     {
  556.         char buf[4];
  557.   
  558.         if(pullup(bpp,buf,4) != 4){
  559.         /* Return zero if insufficient buffer */
  560.             return 0;
  561.         }
  562.         return get32(buf);
  563.     }
  564. /* Pull a 16-bit integer in host order from buffer in network byte order.
  565.  * Return -1 on error
  566.  */
  567.     long
  568.     pull16(bpp)
  569.     struct mbuf **bpp;
  570.     {
  571.         char buf[2];
  572.   
  573.         if(pullup(bpp,buf,2) != 2){
  574.             return -1;              /* Nothing left */
  575.         }
  576.         return get16(buf);
  577.     }
  578. /* Pull single character from mbuf */
  579.     int
  580.     pullchar(bpp)
  581.     struct mbuf **bpp;
  582.     {
  583.         char c;
  584.   
  585.         if(pullup(bpp,&c,1) != 1)
  586.             return -1;              /* Nothing left */
  587.         return (int)uchar(c);
  588.     }
  589.     int
  590.     write_p(fp,bp)
  591.     FILE *fp;
  592.     struct mbuf *bp;
  593.     {
  594.         while(bp != NULLBUF){
  595.             if(fwrite(bp->data,1,bp->cnt,fp) != bp->cnt)
  596.                 return -1;
  597.             bp = bp->next;
  598.         }
  599.         return 0;
  600.     }
  601.   
  602. #ifndef LINUX
  603. /* Reclaim unused space in a mbuf chain. If the argument is a chain of mbufs
  604.  * and/or it appears to have wasted space, copy it to a single new mbuf and
  605.  * free the old mbuf(s). But refuse to move mbufs that merely
  606.  * reference other mbufs, or that have other headers referencing them.
  607.  *
  608.  * Be extremely careful that there aren't any other pointers to
  609.  * (or into) this mbuf, since we have no way of detecting them here.
  610.  * This function is meant to be called only when free memory is in
  611.  * short supply.
  612.  */
  613.     void
  614.     mbuf_crunch(bpp)
  615.     struct mbuf **bpp;
  616.     {
  617.         register struct mbuf *bp = *bpp;
  618.         struct mbuf *nbp;
  619.   
  620.         if(bp->refcnt > 1 || bp->dup != NULLBUF){
  621.         /* Can't crunch, there are other refs */
  622.             return;
  623.         }
  624.         if(bp->next == NULLBUF && bp->cnt == bp->size){
  625.         /* Nothing to be gained by crunching */
  626.             return;
  627.         }
  628.         if((nbp = copy_p(bp,len_p(bp))) == NULLBUF){
  629.         /* Copy failed due to lack of (contiguous) space */
  630.             return;
  631.         }
  632.         nbp->anext = bp->anext;
  633.         free_p(bp);
  634.         *bpp = nbp;
  635.     }
  636. #endif /* LINUX */
  637.   
  638.