V8/usr/sys/chaosld/chpacket.c

Compare this file to the similar file:
Show the results in this format:

/*
 *             C H  P A C K E T
 *
 * Packet handling utilities for the Chaosnet line discipline.
 *
 *
 * (c) Copyright 1985  Nirvonics, Inc.
 *
 * Written by Kurt Gollhardt
 * Last update Thu Feb 28 14:44:14 1985
 *
 * This software is the property of Nirvonics, Inc.
 * All rights reserved.
 *
 */

#include "ch.h"
#if NCH > 0
#include "../h/param.h"
#include "../h/systm.h"
#include "../h/stream.h"
#include "../h/conf.h"
#include "../chaosld/types.h"
#include "../chaosld/constants.h"
#include "../chaosld/globals.h"

#define CAREFUL


     /*
      * Get blocks from a queue, up to the next delimiter,
      * and place them into a packet structure.
      */

struct packet *get_packet(q, wflag)
     register struct queue    *q;
{
     register struct packet   *pk;
     register struct block    *bp, **nextbp;
     register int   len;

     len = wflag? 1 : sizeof(struct pkt_header);
     if ((bp = getq(q)) == NOBLOCK)
          return NOPKT;

#ifdef CAREFUL
     if (bp->type != M_DATA ||
               bp->wptr - bp->rptr < len) {
	  freeb(bp);
          printf("bad block in get_packet()\n");
	  return NOPKT;
     }
#endif CAREFUL

     if ((pk = pkalloc()) == NOPKT) {
          freeb(bp);
	  flush_packet(q);
	  return NOPKT;
     }

     if (wflag)
          pk->pk_op = *bp->rptr++;
     else {
          pk->ph = *(struct pkt_header *)(bp->rptr);
          bp->rptr += sizeof(struct pkt_header);
     }
     if (bp->rptr >= bp->wptr) {
          freeb(bp);
	  bp = getq(q);
     }

     pk->pk_lenword = 0;
     nextbp = &pk->data;
     while (bp != NOBLOCK && bp->type != M_DELIM) {
          pk->pk_lenword += bp->wptr - bp->rptr;
          *nextbp = bp;
	  nextbp = &bp->next;
	  bp = getq(q);
     }
     *nextbp = NOBLOCK;
     if (bp != NOBLOCK)
          freeb(bp);     /* Throw away the delimiter */

     pk->time = Chclock;
     pk->next = NOPKT;
     return pk;
}


     /*
      * Take the header and data blocks from a packet
      * and put them onto the queue.
      * Any storage associated with the packet is freed.
      */

put_packet(q, pk)
     struct queue   *q;
     struct packet  *pk;
{
     putcpy(q->next, &pk->ph, sizeof(struct pkt_header));
     put_pkdata(q, pk);
}


     /*
      * Take the data blocks from a packet
      * and put them onto the queue.
      * Any storage associated with the packet is freed.
      */

put_pkdata(q, pk)
     register struct queue    *q;
     register struct packet   *pk;
{
     register struct block    *bp, *nextb;

     for (bp = pk->data; bp != NOBLOCK; bp = nextb) {
          nextb = bp->next;
	  (*q->next->qinfo->putp) (q->next, bp);
     }

     if (q->flag & QDELIM)
          putctl(q->next, M_DELIM);

     pk->data = NOBLOCK;
     free_packet(pk);
}


     /*
      * Copy the header and data blocks from a packet onto a queue.
      */

copy_packet(q, pk)
     struct queue   *q;
     struct packet  *pk;
{
     putcpy(q->next, &pk->ph, sizeof(struct pkt_header));
     copy_pkdata(q, pk);
}


     /*
      * Copy the data blocks from a packet onto a queue.
      */

copy_pkdata(q, pk)
     register struct queue    *q;
     register struct packet   *pk;
{
     register struct block    *bp;

     for (bp = pk->data; bp != NOBLOCK; bp = bp->next)
          putcpy(q->next, bp->rptr, bp->wptr - bp->rptr);
     putctl(q->next, M_DELIM);
}


     /*
      * Obtain storage for a packet and perfrom minimal initialization.
      */

struct packet *
new_packet()
{
     register struct packet   *pk;

     if ((pk = pkalloc()) == NOPKT)
          return NOPKT;
     bfill(pk, sizeof(struct packet), 0);
     pk->time = Chclock;
     return pk;
}


     /*
      * Release all storage associated with a packet structure.
      */

free_packet(pk)
     register struct packet   *pk;
{
     free_pkdata(pk);
     pkfree(pk);
}


     /*
      * Release all data blocks in packet.
      */

free_pkdata(pk)
     register struct packet   *pk;
{
     register struct block    *bp, *nextb;

     for (bp = pk->data; bp != NOBLOCK; bp = nextb) {
          nextb = bp->next;
	  freeb(bp);
     }
     pk->data = NOBLOCK;
     pk->pk_lenword = 0;
}


     /*
      * Collapse all of the data blocks for a packet
      * into a single block if possible
      */

flatten(pk)
     register struct packet   *pk;
{
     register struct block    *bp, *bigb, *nextb;
     register int        n;
     int       ps;

     debug(DPKT,printf("flatten packet of length %d\n", pk->pk_len));
     if (pk->data->wptr - pk->data->rptr >= pk->pk_len)
          return 0;
     if ((bigb = allocb(pk->pk_len)) == NOBLOCK) {
          debug(DPKT|DABNOR,printf("flatten: can't alloc block\n"));
          return -1;
     }
     bigb->next = NOBLOCK;
     bp = pk->data;
     ps = spl6();
     pk->data = bigb;

     while (bp != NOBLOCK) {
          n = bp->wptr - bp->rptr;
	  if (bigb->lim - bigb->wptr < n)
	       n = bigb->lim - bigb->wptr;
          bcopy(bp->rptr, bigb->wptr, n);
	  bigb->wptr += n;
	  bp->rptr += n;
	  if (bp->rptr < bp->wptr) {
	       bigb->next = bp;
	       splx(ps);
	       debug(DPKT|DABNOR,printf("flatten: not enough room in block\n"));
	       return -1;
          }
          nextb = bp->next;
	  freeb(bp);
	  bp = nextb;
     }

     splx(ps);
     return 0;
}


     /*
      * Add some bytes of data to the end of a packet.
      * Allocate blocks as necessary.
      */

append_packet(pkt, buf, n)
     register struct packet   *pkt;
     char      *buf;
     int       n;
{
     register struct block    *bp;
     register int        nmin;

     if (pkt->data == NOBLOCK) {
          if ((bp = allocb(n)) == NOBLOCK)
	       return;
          pkt->data = bp;
	  bp->next = NOBLOCK;
     } else {
          for (bp = pkt->data; bp->next != NOBLOCK; bp = bp->next)
	       ;
     }

     while (n > 0) {
          if (bp->wptr == bp->lim) {
	       if ((bp->next = allocb(n)) == NOBLOCK)
	            return;
	       bp = bp->next;
	       bp->next = NOBLOCK;
          }
	  nmin = bp->lim - bp->wptr;
	  if (nmin > n)
	       nmin = n;
          bcopy(buf, bp->wptr, nmin);
          buf += nmin;
	  bp->wptr += nmin;
	  pkt->pk_lenword += nmin;
	  n -= nmin;
     }
}


/*
 * Free a list of packets
 */
freelist(pkt)
register struct packet *pkt;
{
     register struct packet *opkt;

     while ((opkt = pkt) != NOPKT) {
          pkt = pkt->next;
          free_packet(opkt);
     }
}