V8/usr/sys/chaosld/chaosld.c

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

/*
 *             C H A O S  L D
 *
 * Chaosnet line discipline, to be pushed on an ethernet controller.
 * Handles xmit and rcv windows, packet numbering, and connection states.
 *
 *
 * (c) Copyright 1985  Nirvonics, Inc.
 *
 * Written by Kurt Gollhardt
 * Last update Tue Mar 12 04:18:58 1985
 *
 * This software is the property of Nirvonics, Inc.
 * All rights reserved.
 *
 */

#include "ch.h"
#if NCH
#include "../h/param.h"
#include "../h/systm.h"
#include "../h/stream.h"
#include "../h/ioctl.h"
#include "../h/ttyld.h"
#include "../h/map.h"
#include "../h/buf.h"
#include "../h/conf.h"
#include "../chaosld/types.h"
#define CHDEFINE
#include "../chaosld/globals.h"


extern int     chrcv(), chb_put();
int            chopen(), chclose(), chosrv(), chisrv();
static struct qinit chrinit = { chb_put, chisrv, chopen, chclose, 512, 64 };
static struct qinit chwinit = { putq, chosrv, chopen, chclose, 512, 64 };
struct streamtab chinfo = { &chrinit, &chwinit };

chopen(q, dev)
     register struct queue *q;
{
     if (q->ptr)
          return(1);
     if (ChaosQ != (struct queue *)0)   /* Already open */
          return(0);
     ChaosQ = q;     /* that's the RD q */
     q->flag |= QDELIM|QNOENB;     /* chiput calls qenable() */
     WR(q)->flag |= QDELIM;
     return(1);
}

chclose(q)
     struct queue   *q;
{
     struct connection   **connp;
     int       ps = spl6();

     for (connp = Chconn; connp < &Chconn[NCH]; ++connp)
          if (*connp != NOCONN)
	       chld_close(*connp, NOPKT);

     freelist(Chlsnlist);
     freelist(Chrfclist);
     Chlsnlist = Chrfclist = Chrfctail = NOPKT;
     Chmyaddr.ch_addr = 0;

     ChaosQ = (struct queue *)0;
     splx(ps);
}


chisrv(q)
     struct queue   *q;
{
     register struct block    *bp;

     chrcv(q);   /* Receive the packet */

     /* See if there's another packet on the queue */
     for (bp = q->first; bp != NOBLOCK; bp = bp->next)
	  if (bp->type == M_DELIM) {
	       qenable(q);    /* re-enable queue for the next packet */
	       break;
          }
}


chosrv(q)
     register struct queue *q;
{
     register union stmsg *sp;
     register struct block *bp;

     while(bp = getq(q)){
          if(bp->type == M_IOCTL){
               sp = (union stmsg *)bp->rptr;
               switch(sp->ioc0.com){
	            case CHIOCNAME:
		         copyin(*(caddr_t *)sp->iocx.xxx, Chmyname, CHSTATNAME);
                         bp->rptr = bp->wptr;
			 bp->type = M_IOCACK;
			 qreply(q, bp);
			 break;
	            case CHIOCADDR:
		         Chmyaddr.ch_addr = *(int *)sp->iocx.xxx;
			 /* fall through */
                    default:
                         (*q->next->qinfo->putp)(q->next, bp);
                         break;
               }
          } else
               (*q->next->qinfo->putp)(q->next, bp);
     }
}

chld_write(conn, pkt)
     register struct connection    *conn;
     register struct packet        *pkt;
{
     setconn(conn, pkt);

     switch (pkt->pk_op) {
          case ANSOP:
	  case FWDOP:
	       if (conn->cn_state != CSRFCRCVD ||
	                 (conn->cn_flags & CHANSWER) == 0)
                    goto err;
               chld_close(conn, pkt);
	       return 0;
          case RFCOP:
          case BRDOP:
	       if (conn->cn_state != CSRFCSENT)
	            goto err;
               break;
          case UNCOP:
	       pkt->pk_pkn = 0;
	       pkt->next = NOPKT;
	       senddata(pkt);
	       return 0;
          default:
	       if (!ISDATA(pkt))
	            goto err;
          case OPNOP:
	  case EOFOP:
	       if (conn->cn_state != CSOPEN)
	            goto err;
               setack(conn, pkt);
               break;
     }

     pkt->pk_pkn = ++conn->cn_tlast;
     senddata(pkt);
     return 0;

err:
     free_packet(pkt);
     return -1;
}


chld_eof(conn)
     struct connection   *conn;
{
     register struct packet   *pkt;

     if ((pkt = new_packet()) != NOPKT) {
	  setconn(conn, pkt);
          pkt->pk_op = EOFOP;
	  return chld_write(conn, pkt);
     }
     return 0;
}


chld_accept(conn)
     struct connection   *conn;
{
     conn->cn_state = CSOPEN;
     sendopn(conn);
}


chld_open(conn, daddr, rwsize, pkt)
     register struct connection    *conn;
     register struct packet   *pkt;
{
     conn->cn_faddr.ch_addr = daddr;
     conn->cn_state = CSRFCSENT;
     conn->cn_rwsize = rwsize;
     conn->cn_rsts = rwsize / 2;
     conn->cn_time = Chclock;
     pkt->pk_op = RFCOP;
     pkt->pk_fc = pkt->pk_ackn = 0;
     debug(DCONN,printf("Conn #%x: RFCS state\n", conn->cn_lidx.ci_idx));
     /*
      * By writing the RFC packet like a data packet, it will be kept
      * around for automatic retransmission until freed by the normal
      * receipting mechanism; xmitdone() and chrcv() facilitate this.
      * Since new_conn() clears the connection (including cn_tlast),
      * the packet number of the RFC will be 1 (pkn = ++cn_tlast).
      */
     chld_write(conn, pkt);
}


chld_listen(conn, rwsize, pkt)
     register struct connection    *conn;
     register struct packet   *pkt;
{
     register struct packet   *opkt, *pktl;
     int       ps;

     conn->cn_state = CSLISTEN;
     conn->cn_flags |= CHSERVER;
     conn->cn_rwsize = rwsize;
     pkt->pk_op = LSNOP;
     setconn(conn, pkt);

     if (flatten(pkt)) {
          free_packet(pkt);
	  return;
     }

     ps = spl6();
     opkt = NOPKT;
     for (pktl = Chrfclist; pktl != NOPKT; pktl = (opkt = pktl)->next)
          if (concmp(pktl, pkt->data->rptr, (int)pkt->pk_len)) {
	       if (opkt == NOPKT)
	            Chrfclist = pktl->next;
               else
	            opkt->next = pktl->next;
               if (pktl == Chrfctail)
	            Chrfctail = opkt;
               free_packet(pkt);
	       lsnmatch(pktl, conn);
	       chd_newstate(conn);
	       splx(ps);
	       return;
          }

     pkt->next = Chlsnlist;
     Chlsnlist = pkt;
     splx(ps);

     debug(DCONN,printf("Conn #%x: LISTEN state\n", conn->cn_lidx.ci_idx));
}


chld_close(conn, pkt)
     register struct connection    *conn;
     register struct packet        *pkt;
{
     int       ps = spl6();

     ch_busy++;
     switch (conn->cn_state) {
          case CSOPEN:
	  case CSRFCRCVD:
	       if (pkt != NOPKT) {
	            setconn(conn, pkt);
		    pkt->pk_ackn = pkt->pk_pkn = 0;
		    sendctl(pkt);
		    pkt = NOPKT;
               }
	       /* Fall into ... */
          case CSRFCSENT:
	       close_conn(conn, CSCLOSED, NOPKT);
	       break;
          case CSLISTEN:
	       rmlisten(conn);
	       break;
     }
     --ch_busy;
     splx(ps);

     if (pkt != NOPKT)
          free_packet(pkt);
}

#endif