|
|
Power 6/32 Unix version 1.2b
#include "../bsc/local.h"
#include "../bsc/bscio.h"
#include "../bsc/bsc.h"
/* D.L.Buck and Associates, Inc. - %H%
*
* COPYRIGHT NOTICE:
* Copyright c %H% - An unpublished work by
* D.L.Buck and Associates, Inc.
*
* PROPRIETARY RIGHTS NOTICE:
* All rights reserved. This document and program contains
* proprietary information of D.L.Buck and Associates,Inc.
* of San Jose, California, U.S.A., embodying confidential
* information, ideas, and expressions, no part of which
* may be reproduced, or transmitted in any form or by any
* means, electronic, mechanical, or otherwise, without
* the written permission of D.L.Buck and Associates, Inc.
*
* NAME
* bscpsm -- BISYNC Single- or Multi-station Protocol State Machine
*
* DESCRIPTION
* The BISYNC protocol is implemented via a state machine. The state
* machine consists of a state table, the state machine algorithm,
* and a set of state actions.
*
* Each state in the state machine is either a 'send', 'receive',
* 'decision', 'function', or 'error' state. Each has a particular
* action associated with it. Before defining the state table for the
* protocol state machine, we introduce the state enumerations for use
* in subsequent definitions.
*/
#ifndef lint
static char bscpm_c[] = "%W% %Q%";
#endif
long TWAIT = 2;
#define START 0 /* starting state */
#define PTPT 1 /* Starting state for point-to-point */
#define SNDBID 2 /* pt-pt write; send bid */
#define WTBIDA 3 /* wait bid acknowledgement */
#define CKHOST 4 /* check host id */
#define CKXMIT 5 /* check transmit buffer */
#define SNDTXT 6 /* send text block */
#define WTTXTA 7 /* wait text acknowledgement */
#define RGTACK 8 /* check for correct ack */
#define XFLIP 9 /* flip even/odd block indicator */
#define SNDTTD 10 /* text buffer empty - send ttd */
#define WTTTDA 11 /* wait for ttd acknowledgement */
#define PROERR 12 /* error - protocol violation */
#define SNDEOT 13 /* send eot */
#define RTYERR 14 /* error - # retries exceeded */
#define WNGACK 15 /* wrong acknowledgement */
#define CKNWAK 16 /* check wack counter */
#define WAKERR 17 /* error - too many wack's */
#define CKNRTY 18 /* check # retries */
#define CHKRVI 19 /* check action on rvi */
#define RVIERR 20 /* error - rvi received */
#define RTOENQ 21 /* send enq for timeout */
#define WTRTOA 22 /* wait for response to timeout enq */
#define CKNRT2 23 /* check # retries */
#define CORACK 24 /* check for correct acknowledgement */
#define BIDEOT 25 /* send eot then rebid */
#define CKNBID 26 /* check # bids sent */
#define BIDERR 27 /* error - bid count exceeded */
#define HSTERR 28 /* error - wrong host id */
#define DONE 29 /* transmit complete */
#define WTPTPT 30 /* wait for point-to-point enq */
#define SETODD 31 /* set odd block count */
#define CKRDY 32 /* check rcv buffer availability */
#undef DELAY
#define DELAY 33 /* send wack */
#define WTWAKA 34 /* wait wack acknowledgement */
#define SNDLST 35 /* send last acknowledgement */
#define WTTEXT 36 /* receive text */
#define CKBCC 37 /* check bcc */
#define NAKERR 38 /* error - too many nak's */
#define SNDNAK 39 /* send nak */
#define CKNTTD 40 /* check # ttd's */
#define TTDERR 41 /* error - too many ttd's */
#define CKABTM 42 /* check for abnormal termination */
#define RXEEOF 43 /* error - early eof */
#define RDONE 44 /* receive complete */
#define SNDDSC 45 /* line closed - send disconnect */
#define XTO 46 /* error - transmit timeout */
#define NODSR 47 /* error - modem dropped DSR */
#define CONTND 48 /* error - line contention on send */
#define MPT 49 /* multipoint poll receive */
#define CKMPT 50 /* check multipoint address */
#define MPTCNT 51 /* mulipoint contention */
#define FASTAK 52 /* fast acknowledge */
#define POLEOT 53 /* send eot to poll */
#define TOOBIG 54 /* Received block was greater than BSCMBLK */
#define SETLST 55 /* Set "last sent" to ack0/1 */
extern long nvbsc;
extern struct bsc bsc[];
#ifdef NBSM
extern struct bscsub bscsubs[NBSM][NBSSUB];
extern char ascdev[],ebcdev[];
#endif
/*
* There are NX different transmission messages, as follows:
*/
#define X_BID 0 /* initial bid request */
#define X_TXT 1 /* text message */
#define X_TTD 2 /* temporary transmit delay */
#define X_EOT 3 /* end of transmission */
#define X_ENQ 4 /* repeat last message request */
#define X_LST 5 /* send last acknowledgement */
#define X_WAK 6 /* acknowledge with wait request */
#define X_NAK 7 /* negative acknowledgement */
#define X_DSC 8 /* disconnect */
#define X_BAK 9 /* bid acknowledgement */
#define NX 10 /* number of transmission messages */
/* These are the ASCII messages and message components: */
typedef struct xlist xl;
/* initial bid */
xl ascbid[] = { { 0, 0 }, { 1, "\005" }, {0,0} };
/* init bid response */
xl ascbak[] = { { 0, 0 }, { 2, "\020\060" }, {0,0} };
/* text block */
xl asctxt[] = { { 1, "" }, /* stx or soh */
{ 0, "" }, /* data */
{ 0, "\020" }, /* if transparent, len = 1 */
{ 0, "" }, /* etb or etx */
#ifdef MANCRC
{ 1, "" }, /* crc */
#endif
{0,0} }; /* changed! */
xl astx = { 1, "\002" }; /* start of text block */
xl atstx = { 2, "\020\002" }; /* start of transparent text block */
xl asoh = { 1, "\001" }; /* start of header */
xl atsoh = { 2, "\020\001" }; /* start of transparent header */
xl aetb = { X_CRC|1, "\027" }; /* end intermediate text blk */
xl aetx = { X_CRC|1, "\003" }; /* end last text block */
xl ascttd[] = { { 2, "\002\005" }, {0,0} }; /* temp. xmit delay */
xl asceot[] = { { 1, "\004" }, {0,0} }; /* end of transmission */
xl ascenq[] = { { 1, "\005" }, {0,0} }; /* enquiry */
xl asclst[] = { { 2, "" }, {0,0} }; /* changed! */
xl aack0 = {2, "\020\060" }; /* even acknowledgement */
xl aack1 = {2, "\020\061" }; /* odd acknowledgement */
xl ascwak[] = { { 2, "\020\073" }, {0,0} }; /* acknowledge with wait */
xl ascnak[] = { { 1, "\025" }, {0,0} }; /* negative acknowledgement */
xl ascdsc[] = { { 2, "\020\004" }, {0,0} }; /* disconnect sequence */
xl *asclist[] = {ascbid, asctxt, ascttd, asceot, ascenq, asclst, ascwak,
ascnak, ascdsc, ascbak};
/* ebcdic transmit lists */
/* initial bid */
xl ebcbid[] = { { 0, 0 }, { 1, "\055" }, {0,0} };
/* init bid response */
xl ebcbak[] = { { 0, 0 }, { 2, "\020\160" }, {0,0} };
/* text block */
xl ebctxt[] = { { 1, "" }, /* stx or soh */
{ 0, "" }, /* data */
{ 0, "\020" }, /* if transparent, len = 1 */
{ 0, "" }, /* etb or etx */
#ifdef MANCRC
{ 2, "" }, /* crc */
#endif
{0,0} }; /* changed! */
xl estx = { 1, "\002" }; /* start of text block */
xl etstx = { 2, "\020\002" }; /* start of transparent text block */
xl esoh = { 1, "\001" }; /* start of header */
xl etsoh = { 2, "\020\001" }; /* start of transparent header */
xl eetb = { X_CRC|1, "\046" }; /* end intermediate text blk */
xl eetx = { X_CRC|1, "\003" }; /* end last text block */
xl ebcttd[] = { { 2, "\002\055" }, {0,0} }; /* temp. xmit delay */
xl ebceot[] = { { 1, "\067" }, {0,0} }; /* end of transmission */
xl ebcenq[] = { { 1, "\055" }, {0,0} }; /* enquiry */
xl ebclst[] = { { 2, "" }, {0,0} }; /* changed! */
xl eack0 = {2, "\020\160" }; /* even acknowledgement */
xl eack1 = {2, "\020\141" }; /* odd acknowledgement */
xl ebcwak[] = { { 2, "\020\153" }, {0,0} }; /* acknowledge with wait */
xl ebcnak[] = { { 1, "\075" }, {0,0} }; /* negative acknowledgement */
xl ebcdsc[] = { { 2, "\020\067" }, {0,0} }; /* disconnect sequence */
xl *ebclist[] = {ebcbid, ebctxt, ebcttd, ebceot, ebcenq, ebclst, ebcwak,
ebcnak, ebcdsc, ebcbak};
/* receive lists - both transmission codes
*
* Each receive list is a string of the different states to which to
* transfer based on the level-0 packet classification.
* This string indexed by a frame type (see bsc.h) gives the state for the
* corresponding packet class.
*/
char rlbida[NC] = {
/* - enq - eot - nak - etx - etb - wak - rvi - ak0 - ak1 - ttd */
CKNBID,CKNBID,BIDEOT,BIDEOT,BIDEOT,CKNBID,BIDEOT,CKHOST,BIDEOT,BIDEOT};
char rltxta[NC] = {
/* - enq - eot - nak - etx - etb - wak - rvi - ak0 - ak1 - ttd */
PROERR,PROERR,CKNRTY,FASTAK,FASTAK,CKNWAK,CHKRVI,RGTACK,RGTACK,PROERR};
char rlttda[NC] = {
/* - enq - eot - nak - etx - etb - wak - rvi - ak0 - ak1 - ttd */
PROERR,PROERR,CKXMIT,PROERR,PROERR,PROERR,PROERR,PROERR,PROERR,PROERR};
char rlrtoa[NC] = {
/* - enq - eot - nak - etx - etb - wak - rvi - ak0 - ak1 - ttd */
CKNRT2,PROERR,CKNRTY,FASTAK,FASTAK,CKNWAK,CHKRVI,CORACK,CORACK,CKNRT2};
char rlptpt[NC] = {
/* - enq - eot - nak - etx - etb - wak - rvi - ak0 - ak1 - ttd */
SETODD,WTPTPT,WTPTPT,WTPTPT,WTPTPT,WTPTPT,WTPTPT,WTPTPT,WTPTPT,WTPTPT};
char rltext[NC] = {
/* - enq - eot - nak - etx - etb - wak - rvi - ak0 - ak1 - ttd */
SETLST,CKABTM,WTTEXT,CKBCC, CKBCC, WTTEXT,WTTEXT,WTTEXT,WTTEXT,CKNTTD};
char rlwaka[NC] = {
/* - enq - eot - nak - etx - etb - wak - rvi - ak0 - ak1 - ttd */
CKRDY,RXEEOF,WTWAKA,PROERR,PROERR,WTWAKA,WTWAKA,WTWAKA,WTWAKA,PROERR};
char rlwtps[NC] = {
/* - enq - eot - nak - etx - etb - wak - rvi - ak0 - ak1 - ttd */
CKMPT, CKMPT, MPT, MPT, MPT, MPT, MPT, MPT, MPT, MPT };
/*
* There are NR different receive lists, as shown above; these
* are numbered for use in the protocol state entry for a receive
* operation. The following constants index 'rlist' to provide a pointer
* to the appropriate receive list.
*/
#define R_BIDA 0 /* bid acknowledgement wait */
#define R_TXTA 1 /* text acknowledgement wait */
#define R_TTDA 2 /* temp. text delay ack. wait */
#define R_RTOA 3 /* response time out wait */
#define R_PTPT 4 /* point-to-point bid wait */
#define R_TEXT 5 /* wait for text */
#define R_WAKA 6 /* wait for response to wack message */
#define R_POLSEL 7 /* wait for poll/select */
#define NR 8 /* number of receive lists */
char *rlist[NR] = {rlbida, rltxta, rlttda, rlrtoa, rlptpt, rltext, rlwaka,
rlwtps};
/*
* PSM states may consist of decision functions, which decide for themselves
* what the following state will be, and ordinary functions, which have the
* next state decided for them in the PSM state table.
* Each function is represented by an ordinal in the state table, as follows:
*/
#define D_START 0 /* decide multipoint vs point-to-point */
#define D_PTPT 1 /* decide on send vs receive */
#define D_CKHOST 2 /* check correctness of host id */
#define D_CKXMIT 3 /* check status of xmit buffer */
#define D_RGTACK 4 /* check to see if ack is right */
#define D_XFLIP 5 /* flip even/odd indicator - block recv'd */
#define D_CKNWAK 6 /* check max wacks allowed */
#define D_CKNRTY 7 /* check max retries allowed */
#define D_CHKRVI 8 /* check rvi action */
#define D_CKNRT2 9 /* check max retries allowed */
#define D_CORACK 10 /* check current vs previous ack */
#define D_CKNBID 11 /* check max bids allowed */
#define F_SETODD 12 /* set odd block expected */
#define D_CKRDY 13 /* check status of rcv buffer */
#define D_CKBCC 14 /* check last block's crc */
#define D_CKNTTD 15 /* check max ttd's allowed */
#define D_CKABTM 16 /* check for normal transmission termination */
#define D_CKMPT 17 /* check poll/select address */
#define D_FASTACK 18 /* wait during fast acknowledge */
#define F_SETLST 19 /* Set even/odd ackn. message */
struct state states[] = {
{ 'd', 0, D_START }, /* 0 decide on pt-pt vs multipoint */
{ 'd', 0, D_PTPT }, /* 1 decide on send vs receive */
{ 's', WTBIDA, X_BID }, /* 2 send ENQ (bid) */
{ 'r', CKNBID, R_BIDA },/* 3 receive bid acknowledgement */
{ 'd', 0, D_CKHOST }, /* 4 check to see if right host id */
{ 'd', 0, D_CKXMIT }, /* 5 check for full transmit buffer */
{ 's', WTTXTA, X_TXT }, /* 6 send stx, data, et[bx], ... */
{ 'r', RTOENQ, R_TXTA}, /* 7 wait text acknowledgement */
{ 'd', 0, D_RGTACK }, /* 8 check for correct acknowledgement */
{ 'f', CKXMIT, D_XFLIP},/* 9 flip even/odd indicator */
{ 's', WTTTDA, X_TTD }, /* 10 send temp. text delay */
{ 'r', CKXMIT, R_TTDA },/* 11 wait proper response (nak) */
{ 'e', SNDEOT,BSCPROTO},/* 12 protocol error - funny response */
{ 's', START, X_EOT }, /* 13 send eot */
{ 'e', SNDEOT,BSCNRETR},/* 14 NRETRY limit exceeded */
{ 's', WTTXTA, X_ENQ}, /* 15 wrong ack - send enq */
{ 'd', 0, D_CKNWAK }, /* 16 check # wacks received in a row */
{ 'e', SNDEOT,BSCNWACK},/* 17 NWACK limit exceeded */
{ 'd', 0, D_CKNRTY }, /* 18 check # retries */
{ 'd', 0, D_CHKRVI }, /* 19 check whether we abort or accept RVI */
{ 'e', SNDEOT, BSCRVI },/* 20 error - RVI received */
{ 's', WTRTOA, X_ENQ }, /* 21 receive timeout - send ENQ */
{ 'r', CKNRT2, R_RTOA },/* 22 wait on acknowledgement to ENQ */
{ 'd', 0, D_CKNRT2 }, /* 23 check # retries */
{ 'd', 0, D_CORACK }, /* 24 check to see if we resend text */
{ 's', CKNBID, X_EOT }, /* 25 bad response to bid */
{ 'd', 0, D_CKNBID }, /* 26 check # bids */
{ 'e', SNDEOT, BSCNBID},/* 27 error - too many unanswered bids */
{ 'e', SNDEOT, BSCWHI}, /* 28 error - wrong host */
{ 'e', SNDEOT, 0 }, /* 29 done! */
{ 'r', WTPTPT, R_PTPT },/* 30 wait for line bid from other end */
{ 'f', CKRDY, F_SETODD},/* 31 set odd response indicator */
{ 'd', 0, D_CKRDY }, /* 32 check receive buffer available */
{ 's', WTWAKA, X_WAK }, /* 33 buffer unavailable - send wack */
{ 'r', WTWAKA, R_WAKA}, /* 34 wait wack acknowledgement */
{ 's', WTTEXT, X_LST }, /* 35 send 'last response' */
{ 'r', WTTEXT, R_TEXT}, /* 36 wait for text */
{ 'd', 0, D_CKBCC }, /* 37 check bcc (crc or lrc) */
{ 'e', SNDEOT, BSCNNAK},/* 38 error - nak limit exceeded */
{ 's', WTTEXT, X_NAK }, /* 39 send nak (to TTD or bad text block) */
{ 'd', 0, D_CKNTTD }, /* 40 check TTD limits */
{ 'e', SNDEOT, BSCNTTD},/* 41 error - TTD limit exceeded */
{ 'd', 0, D_CKABTM }, /* 42 check for normal eof or early eof */
{ 'e', 0, BSCEEOF }, /* 43 early end of file */
{ 'e', 0, 0 }, /* 44 normal end of receive */
{ 's', START, X_DSC}, /* 45 send disconnect message */
{ 'e', 0, BSCTXTO }, /* 46 error - xmit timeout */
{ 'e', 0, BSCNDSR }, /* 47 error - no DSR */
{ 'e', SNDEOT,BSCONTND},/* 48 error - line contention */
{ 'r', MPT, R_POLSEL }, /* 49 MPT Wait Poll/Select */
{ 'd', 0, D_CKMPT }, /* 50 CKMPT Check Poll/select address */
{ 'e', MPT, BSCONTND }, /* 51 MPTCNT Multipoint contention */
{ 'd', CKBCC,D_FASTACK},/* 52 FASTAK Wait during fast acknowledge */
{ 's', MPT, X_EOT }, /* 53 POLEOT Respond negatively to poll */
{ 'e', SNDEOT, BSC2BIG},/* 54 TOOBIG Rcvd block was too big */
{ 'f', SNDLST,F_SETLST},/* 55 SETLST Set even/odd last send pointer */
};
bscpsm(dev) /* protocol state machine */
register dev_t dev;
{
register struct bsc *bp;
#ifdef NBSM
register struct bscsub *bsp;
#endif
register struct state *st;
int x,xx;
register int iflag, dflag;
if (dev >= MX_NBSC)
panic("bsc: unknown device#");
bp = &bsc[dev];
x = spl8(); /* Lock the door */
if (bp->b_sema & BSC_INPSM) { /* Someone have it locked? */
splx(x); /* Yes - leave quietly */
return;
}
bp->b_sema |= BSC_INPSM; /* Make sure no one else enters */
splx(x);
if (bp->b_mode == BSC_CL1) { /* Need to send disconnect */
bp->b_state = SNDDSC; /* New state: send disconnect */
bp->b_mode = BSC_CL2; /* New mode: wait for disc complete */
}
#ifdef NBSM
if (bp->b_lock != SSLOCK)
if (bp->b_psmbsy == -1)
bsp = NULL;
else
bsp = &bscsubs[dev][bp->b_psmbsy];
#endif
/* Main loop of Protocol State Machine */
while (1) {
st = &states[bp->b_state];
/* If tracing engaged, trace this state */
if (bp->b_trace)
bsctr (dev, bp->b_state, st->s_type);
switch (st->s_type) {
case 'f': /* function */
bp->b_state = st->s_next;/* always use table's new st*/
case 'd': /* decision */
iflag = bp->b_hlflgs; /* temp copy of flag */
#ifdef NBSM
dflag = (bp->b_lock == SSLOCK) ? iflag :
(bsp?bsp->bs_flags:0);
/* temp copy of device flags */
#else
dflag = iflag; /* same as iflag */
#endif
switch (st->s_ord) { /* do function */
case D_START:
if (bp->b_mode == BSC_CL2)
bp->b_mode = BSC_CLOSED;
if (bp->b_mode == BSC_CLOSED)
goto closedoor;
#ifdef NBSM
if (bp->b_lock == SSLOCK)
x = bp->b_sema;
else x = (bsp)?bsp->bs_sema:BSC_DDONE;
#else
x = bp->b_sema;
#endif
if (x & BSC_DBUSY) {
x = spl8();
bp->b_alarm = PSMTPS;
bp->b_alenb = 1;
splx(x);
goto closedoor;
}
bp->b_tmperr = 0; /* zero tmperrs */
if (iflag & BSCMPT) { /* if multipoint, */
bp->b_hlflgs |= BSC_POLLWT;
bp->b_state = MPT;
} else
bp->b_state = PTPT;
x = spl8();
bp->b_sema |= BSC_PDONE;
bp->b_sema &= ~BSC_PBUSY;
#ifdef NBSM
if (bp->b_lock != SSLOCK && bsp) {
bsp->bs_sema |= BSC_PDONE;
bsp->bs_sema &= ~BSC_PBUSY;
bsp = NULL;
bp->b_psmbsy = -1;
}
#endif
splx(x);
break;
case D_PTPT:
/* If we are to write, SNDBID; read, WTPTPT;
* otherwise, delay.
*/
/* If ready to write, check initial bid */
for (x=0; x<sizeof bp->b_iocin.b_termid &&
bp->b_iocin.b_termid[x];
++x);
if (bp->b_mode == BSC_WRITE) {
bp->b_state = SNDBID;
bp->b_sema &= ~BSC_PDONE;
bp->b_sema |= BSC_PBUSY;
ascbid[0].xnum = x;
ebcbid[0].xnum = x;
ascbid[0].xptr = bp->b_iocin.b_termid;
ebcbid[0].xptr = bp->b_iocin.b_termid;
break;
}
if (bp->b_mode == BSC_READ) {
bp->b_state = WTPTPT;
bp->b_sema &= ~BSC_PDONE;
bp->b_sema |= BSC_PBUSY;
ascbak[0].xnum = x;
ebcbak[0].xnum = x;
ascbak[0].xptr = bp->b_iocin.b_termid;
ebcbak[0].xptr = bp->b_iocin.b_termid;
break;
}
/* else */
wakeup ((caddr_t)bp->b_buffer);
x = spl8();
bp->b_alarm = PSMTPS; /* wait 1 sec*/
bp->b_alenb = 1;
splx(x);
goto closedoor;
case D_CKHOST:
/* 1. Set expected response to odd ackn.
* Null our term id field - send once only.
* 2. If we are supposed to check host id,
* compare received vs. given.
* If different, HSTERR.
* Normally, CKXMIT.
*/
bp->b_hlflgs |= BSC_ACK; /* set odd */
bp->b_iocin.b_termid[0] = '\0';
bp->b_state = ((!(iflag & BSCCKHOST))
|| bp->b_iocin.b_hostid[0] == '\0'
|| bsccmp(bp->b_iocin.b_hostid,
bp->b_iocout.b_hostid)==0) ?
CKXMIT : HSTERR;
break;
case D_CKXMIT:
/* Check transmit buffer. If empty,
* wait up to 2 seconds; if still
* empty, send TTD.
*/
if (!(dflag & BSC_FULL)) { /* buffer empty */
if (bp->b_alarm <= -100 &&
++bp->b_bscto >= 2*PSMTPS) {
bp->b_bscto = 0;
bp->b_state = SNDTTD;
break;
}
x = spl8();
bp->b_alarm = 1; /* wait 1 tick */
bp->b_alenb = 1; /* enable alarm */
splx(x);
goto closedoor;
}
/* buffer full */
bp->b_bscto = 0;
bp->b_state = SNDTXT; /* send what we got */
if (iflag & BSCASCII) { /* set up text list*/
asctxt[0] = (dflag&BSC_XTRN)?
((dflag&BSC_XSOH)?atsoh:atstx):
((dflag&BSC_XSOH)?asoh : astx);
#ifdef NBSM
if (bp->b_lock != SSLOCK) {
asctxt[1].xnum =
X_CRC|bsp->bs_size;
asctxt[1].xptr =
bsp->bs_buf;
} else {
#endif
asctxt[1].xnum =
X_CRC|bp->b_bsize;
asctxt[1].xptr =
bp->b_buffer;
#ifdef NBSM
}
#endif
asctxt[2].xnum = (dflag&BSC_XTRN)?1:0;
asctxt[3] =
(dflag&BSC_XLAST)?aetx : aetb;
#ifdef MANCRC
asctxt[4].xptr = bp->b_crc;
#endif
} else {
ebctxt[0] = (dflag&BSC_XTRN)?
((dflag&BSC_XSOH)?etsoh:etstx):
((dflag&BSC_XSOH)?esoh : estx);
#ifdef NBSM
if (bp->b_lock != SSLOCK) {
ebctxt[1].xnum =
X_CRC|bsp->bs_size;
ebctxt[1].xptr =
bsp->bs_buf;
} else {
#endif
ebctxt[1].xnum =
X_CRC|bp->b_bsize;
ebctxt[1].xptr =
bp->b_buffer;
#ifdef NBSM
}
#endif
ebctxt[2].xnum = (dflag&BSC_XTRN)?1:0;
ebctxt[3] =
(dflag&BSC_XLAST)?eetx : eetb;
#ifdef MANCRC
ebctxt[4].xptr = bp->b_crc;
#endif
}
break;
case D_RGTACK:
if (bp->b_class1 == ((iflag&BSC_ACK)?C_AK1:C_AK0))
bp->b_state = XFLIP;
else
bp->b_state =
(++bp->b_tmperr >
(bp->b_iocin.b_nretry&0xff))
? RTYERR : WNGACK;
break;
case D_XFLIP:
++bp->b_iocout.b_blks; /* tally # blks sent */
bp->b_tmperr = 0; /* zero tmp error ct */
bp->b_hlflgs ^= BSC_ACK;
#ifdef NBSM
if (bp->b_lock != SSLOCK) {
bsp->bs_flags &= ~BS_FULL;
wakeup ((caddr_t)&bsp->bs_flags);
} else {
#endif
bp->b_hlflgs &= ~BSC_FULL;
wakeup ((caddr_t)bp->b_buffer);
#ifdef NBSM
}
#endif
bp->b_state = (dflag & BSC_XLAST)? DONE : CKXMIT;
break;
case D_FASTACK:
/* Fast acknowledge (text reply to text).
* Wait for write caller to finish
* as indicated by LAST flag going
* off. Wait up to 5 seconds.
* When done, go check bcc on text.
*/
if (bp->b_alarm <= -100) { /* Timeout. */
if (dflag & BSC_XLAST /* waiting on*/
/* end of wrt*/
&& ++bp->b_bscto <= 5*PSMTPS) {
x = spl8();
bp->b_alarm = 1;
bp->b_alenb = 1;
splx(x);
goto closedoor;
}
bp->b_bscto = 0;
bp->b_state = CKBCC; /* done write*/
#ifdef NBSM
if (bp->b_lock != SSLOCK)
bsp->bs_mode = BS_READ;
else
#endif
bp->b_mode = BS_READ;
break;
}
/* 1st time thru -- terminate write */
bp->b_tmperr = 0;
++bp->b_iocout.b_blks;
bp->b_mode = BSC_IDLE;
#ifdef NBSM
if (bp->b_lock != SSLOCK) {
bsp->bs_mode = BS_IDLE;
bsp->bs_flags &= ~BS_FULL;
wakeup ((caddr_t)&bsp->bs_flags);
} else{
#endif
bp->b_hlflgs &= ~BSC_FULL;
wakeup ((caddr_t)bp->b_buffer);
#ifdef NBSM
}
#endif
bp->b_hlflgs |= BSC_ACK;
x = spl8();
bp->b_alarm = 1;
bp->b_alenb = 1;
splx(x);
goto closedoor;
case D_CKNRTY:
++bp->b_iocout.b_nretry; /* tally retries */
bp->b_state =
(++bp->b_tmperr >
(bp->b_iocin.b_nretry&0xff))?
RTYERR:SNDTXT;
break;
case D_CKNWAK:
++bp->b_iocout.b_nwack; /* tally wacks */
bp->b_state =
(++bp->b_tmperr >
(bp->b_iocin.b_nwack&0xff))?
WAKERR:WNGACK;
break;
case D_CHKRVI:
bp->b_state = (iflag&BSCRVIABT)? RVIERR : XFLIP;
break;
case D_CORACK:
bp->b_state = (bp->b_class1==
((iflag&BSC_ACK)?C_AK1:C_AK0))
? XFLIP : SNDTXT;
break;
case D_CKNRT2:
++bp->b_iocout.b_nretry; /* tally retries */
bp->b_state =
(++bp->b_tmperr >
(bp->b_iocin.b_nretry&0xff))?
RTYERR:RTOENQ;
break;
case D_CKNBID:
++bp->b_iocout.b_nbid;
if (!(iflag & BSCPRIM) &&
bp->b_class1 == C_ENQ) {
bp->b_state = CONTND;
break;
}
if (bp->b_iocin.b_nbid == 0 ||
(bp->b_iocin.b_nbid&0xff) >
++bp->b_tmperr) {
bp->b_state = SNDBID;
break;
}
bp->b_state = BIDERR;
break;
case F_SETODD:
if (!(iflag & BSCMPT))
bp->b_iocin.b_termid[0] = '\0';
bp->b_hlflgs |= BSC_ACK;
asclst[0].xptr = aack0.xptr;
ebclst[0].xptr = eack0.xptr;
bp->b_rdflag = 0; /* reset idle t/o */
#ifdef NBSM
if (bp->b_lock != SSLOCK) /* m/station*/
bsp->bs_rdflg = 0;
#endif
break;
case F_SETLST:
/* Set ebclst or asclst to point to proper
* acknowledgement message (even/odd)
*/
if (iflag & BSC_ACK) { /* next msg odd */
/* Response to last should be ACK0 */
asclst[0].xptr = aack0.xptr;
ebclst[0].xptr = eack0.xptr;
} else { /* next msg even */
/* Response to last should be ACK1 */
asclst[0].xptr = aack1.xptr;
ebclst[0].xptr = eack1.xptr;
}
break;
case D_CKRDY:
/* If buffer available,
* send acknowledgement.
* Otherwise, wait up to 2 seconds for it to
* become available. If no luck, DELAY.
*/
if ( (bp->b_lock == SSLOCK &&
bp->b_mode == BSC_WRITE &&
(bp->b_sema & BSC_FACK)) ||
(bp->b_lock != SSLOCK &&
bsp->bs_mode == BS_WRITE &&
(bsp->bs_sema & BSC_FACK)) ) {
bp->b_hlflgs |= BSC_ACK;
bp->b_state = CKXMIT;
bp->b_bscto = 0;
break;
}
if (!(dflag & BSC_FULL)) {
bp->b_state = SETLST;
bp->b_bscto = 0;
break;
}
if (bp->b_alarm <= -100 &&
++bp->b_bscto >= TWAIT*PSMTPS) {/*time out*/
bp->b_bscto = 0;
bp->b_state = DELAY;
break;
}
x = spl8();
bp->b_alarm = 1; /* pause a tick */
bp->b_alenb = 1; /* enable alarm */
splx(x);
goto closedoor;
/* Check text response.
* If CRC error or overrun (block too big), send a NAK,
* unless we've already sent the limit, in which case
* go to error state NAKERR or TOOBIG.
* For no error case, count blocks, set response xmit
* list element, flip even/odd indicator, new state is
* CKRDY. Also mark buffer full and possibly last (if
* received ETX). Wake sleepers.
*/
case D_CKBCC:
if ((iflag & BSC_CRCERR) ||
(bp->b_bsize > BSCMBLK)) {
++bp->b_iocout.b_nnak;
bp->b_hlflgs &= ~BSC_CRCERR;
bp->b_state = SNDNAK;
if (++bp->b_tmperr >
(bp->b_iocin.b_nnak&0xff))
bp->b_state =
(bp->b_bsize > BSCMBLK)?
TOOBIG : NAKERR;
break;
}
bp->b_tmperr = 0; /* reset err cnt*/
++bp->b_iocout.b_blks; /* count blocks */
bp->b_state = CKRDY;
bp->b_hlflgs ^= BSC_ACK;
bp->b_hlflgs |= BSC_FULL;
if (iflag & BSC_XTRN) /* transp.? */
#ifdef NBSM
if (bp->b_lock != SSLOCK)
bsp->bs_err = BSCTXP;
else
#endif
bp->b_iocout.b_flags = BSCTXP;
#ifdef NBSM
if (bp->b_lock != SSLOCK) {
if (bsp->bs_mode == BS_FREE) {
bp->b_hlflgs &= ~BSC_FULL;
break;
}
bsp->bs_flags |= BS_FULL;
wakeup ((caddr_t)&bsp->bs_flags);
break;
}
#endif
wakeup ((caddr_t)bp->b_buffer);
break;
case D_CKNTTD:
++bp->b_iocout.b_nttd;
bp->b_state =
(++bp->b_tmperr >
(bp->b_iocin.b_nttd&0xff))?
TTDERR:SNDNAK;
break;
case D_CKABTM:
bp->b_state = RDONE;
#ifdef NBSM
if (bp->b_lock != SSLOCK && bsp &&
bsp->bs_mode == BS_FREE)
break;
#endif
bp->b_hlflgs |= BSC_XLAST;
if (bp->b_lock != SSLOCK && bsp) {
bsp->bs_flags |= BS_LAST;
wakeup ((caddr_t)&bsp->bs_flags);
break;
}
wakeup ((caddr_t)bp->b_buffer);
break;
case D_CKMPT:
if (bp->b_mode == BSC_CLOSED)
goto closedoor;
if (bp->b_class1 == C_EOT) { /* oops */
bp->b_hlflgs |= BSC_POLLWT;
bp->b_state = MPT;
break;
}
/* First, check out validity */
/* First two characters must be same, */
/* Next two must also, */
/* And first two must be our poll or */
/* select address */
if ((bp->b_iocout.b_hostid[0] !=
bp->b_iocout.b_hostid[1]) ||
((bp->b_iocout.b_hostid[0] !=
bp->b_iocin.b_termid[0]) &&
(bp->b_iocout.b_hostid[0] !=
bp->b_iocin.b_termid[1])) ||
(bp->b_iocout.b_hostid[2] !=
bp->b_iocout.b_hostid[3])) {
/* Not our address, or invalid */
bp->b_hlflgs |= BSC_POLLWT;
bp->b_state = MPT;
break;
}
/* Check subdevice address */
if (bp->b_iocout.b_hostid[2] ==
((iflag&BSCASCII)?0x22:0x7f)) {
/* general poll */
#ifdef NBSM
if (bp->b_lock != SSLOCK) {
for (bsp = bscsubs[dev];
bsp < &bscsubs[dev][NBSSUB];
++bsp) {
if (bsp->bs_mode ==
BS_WRITE)
goto gotone;
}
/* Gen Poll, nothing ready */
bp->b_hlflgs |= BSC_POLLWT;
bp->b_state = POLEOT;
break;
}
#endif
goto gottwo;
}
/* not general poll ... check specific */
#ifdef NBSM
if (bp->b_lock == SSLOCK) {
#endif
if(bp->b_iocout.b_hostid[2] ==
((iflag&BSCASCII)?
0x20:0x40))
goto gottwo;
#ifdef NBSM
} else {
for (x = 0;
x < NBSSUB; ++x)
if (bp->b_iocout.b_hostid[2] ==
((iflag&BSCASCII)?
ascdev:ebcdev)[x]) {
bsp = &bscsubs[dev][x];
goto gotone;
}
}
#endif
/* don't have that device */
bp->b_hlflgs |= BSC_POLLWT;
bp->b_state = POLEOT;
break;
#ifdef NBSM
gotone: bp->b_psmbsy = bsp - bscsubs[dev];
dflag = bsp->bs_flags;
#endif
/* Are we being Polled? */
gottwo:
if (bp->b_iocout.b_hostid[0] ==
bp->b_iocin.b_termid[0]) { /* Poll? */
#ifdef NBSM
if ((bp->b_lock != SSLOCK &&
bsp->bs_mode == BS_WRITE) ||
(bp->b_lock == SSLOCK &&
bp->b_mode == BSC_WRITE)) {
if (bp->b_lock != SSLOCK) {
bsp->bs_sema &=
~BSC_PDONE;
bsp->bs_sema |=
BSC_PBUSY;
}
#else
if (bp->b_mode == BSC_WRITE) {
#endif
/* Polled, ready to send */
bp->b_sema &= ~BSC_PDONE;
bp->b_sema |= BSC_PBUSY;
bp->b_state = CKXMIT;
bp->b_hlflgs |= BSC_ACK;
bp->b_hlflgs &= ~BSC_POLLWT;
} else {
/* Polled, not ready */
bp->b_hlflgs |= BSC_POLLWT;
bp->b_state = POLEOT;
bp->b_psmbsy = -1;
}
break;
}
/* Otherwise, we've been selected */
#ifdef NBSM
if ((!(bp->b_hlflgs & BSC_FULL)) &&
(bp->b_lock != SSLOCK &&
bsp->bs_mode != BS_WRITE) ||
(bp->b_lock == SSLOCK &&
(bp->b_mode == BSC_READ ||
bp->b_mode == BSC_IDLE))) {
if (bp->b_lock != SSLOCK) {
bsp->bs_sema &= ~BSC_PDONE;
bsp->bs_sema |= BSC_PBUSY;
}
#else
if ((!(bp->b_hlflgs & BSC_FULL)) &&
(bp->b_mode == BSC_IDLE ||
bp->b_mode == BSC_READ)) {
#endif
bp->b_sema &= ~BSC_PDONE;
bp->b_sema |= BSC_PBUSY;
bp->b_state = SETODD;
bp->b_hlflgs &= ~BSC_POLLWT;
#ifdef NBSM
if (bp->b_lock != SSLOCK) {
if (bsp->bs_mode != BS_FREE)
bsp->bs_mode = BS_READ;
} else
#endif
bp->b_mode = BSC_READ;
} else { /* Write Contention */
bp->b_hlflgs |= BSC_POLLWT;
bp->b_state = MPTCNT;
bp->b_psmbsy = -1;
}
break;
default: panic("bsc: unknown function#\n");
}
break;
case 's': /* transmit */
{
register struct xlist *xp;
xp = ((bp->b_hlflgs&BSCASCII)?asclist:ebclist)
[st->s_ord];
bp->b_txlst[1] = xp[0];
bp->b_txlst[2] = xp[1];
bp->b_txlst[3] = xp[2];
bp->b_txlst[4] = xp[3];
bp->b_txlst[5] = xp[4];
bp->b_txlst[6] = xp[5];
if (bp->b_trace > 1)
btxtrc(dev, xp, bp->b_state);
bscxmit (dev, (int)st->s_next); /*send list */
/* b_state will be updated at end of xmit */
if (states[st->s_next].s_type == 'r')
bp->b_rclptr = rlist[states[st->s_next].s_ord];
x = spl8(); /* set the alarm clock */
bp->b_alarm = ((st->s_ord == X_TXT)?BSCMBLK/300 + 2:
2)*PSMTPS;
bp->b_alenb = 1; /* enable the alarm clock */
splx(x);
goto closedoor;
}
case 'r': /* receive */
/* 1. Set receive list pointer.
* 2. Set alarm for 4 seconds
* The alarm will set the new state to st->s_next.
*/
bp->b_rclptr = rlist[st->s_ord];
x = spl8();
bp->b_alarm = 4*PSMTPS;
bp->b_alenb = 1; /* enable clock */
splx(x);
/* b_state will be updated at end of receive */
goto closedoor;
case 'e': /* error! */
/*
* 1. Wake any process waiting on the buffer.
* 2. If error given, set error bit and save
* error number.
* 3. Select next state from s_next.
*/
#ifdef NBSM
if (bp->b_lock != SSLOCK && bsp)
wakeup ((caddr_t)&bsp->bs_flags);
else
#endif
wakeup ((caddr_t)bp->b_buffer);
if (bp->b_mode >= BSC_CL1) { /* closing */
bp->b_state = START;
break;
}
if (st->s_ord) { /* if error given, */
#ifdef NBSM
if (bp->b_lock != SSLOCK && bsp) {
bsp->bs_flags &= ~BS_FULL;
bsp->bs_flags |= BS_ERR;/* set err */
bsp->bs_err = st->s_ord;
} else {
#endif
bp->b_hlflgs &= ~BSC_FULL;
bp->b_hlflgs |= BSC_ERR;/* set err */
bp->b_iocout.b_flags = st->s_ord;
#ifdef NBSM
}
#endif
}
bp->b_state = st->s_next; /* select next state */
break;
default:
panic ("bsc: unknown state type!\n");
}
};
closedoor: /* Unlock door and leave */
bp->b_sema &= ~BSC_INPSM;
}
bscpto (dev) /* process timeout */
caddr_t dev;
{
register struct bsc *bp;
register struct state *st;
register struct bscsub *bpsub;
register int i;
bp = &bsc[(dev_t)dev]; /* current dev info */
st = &states[bp->b_state]; /* current state entry */
if (bp->b_mode == BSC_CLOSED) /* closed - no further actions! */
return;
if (bp->b_sema & BSC_INPSM) { /* PSM running? */
goto out;
}
bsckdsr((dev_t)dev,bp); /* local chk for DSR */
if (!(bp->b_hlflgs & BSC_DSR)) {
#ifdef NBSM
if (bp->b_lock != SSLOCK) {
for (i=0; i < NBSSUB; i++) {
bpsub = &bscsubs[(dev_t)dev][i];
bpsub->bs_flags |= BS_ERR;
bpsub->bs_flags &= ~BS_FULL;
bpsub->bs_err = BSCNDSR;
wakeup ((caddr_t)&bpsub->bs_flags);
}
goto out;
}
#endif
bp->b_hlflgs |= BSC_ERR;
bp->b_hlflgs &= ~BSC_FULL;
bp->b_iocout.b_flags = BSCNDSR;
wakeup ((caddr_t)bp->b_buffer);
goto out;
}
/* check for rd idle timeout */
#ifdef NBSM
if(bp->b_lock != SSLOCK){
for(i=0;i<NBSSUB;i++){
bpsub = &bscsubs[(dev_t)dev][i];
if(bpsub->bs_mode == BS_READ && bpsub->bs_rdflg &&
--bpsub->bs_rdflg == 0 ){
bpsub->bs_err = BSCRXTO;
bpsub->bs_flags |= BS_ERR;
bpsub->bs_mode = BS_IDLE;
wakeup ((caddr_t)&bpsub->bs_flags);
goto done;
}
}
} else {
#endif
if (bp->b_rdflag && --bp->b_rdflag == 0 && bp->b_mode == BSC_READ) {
bp->b_rclptr = 0; /* reset receiver */
brxres((dev_t)dev);
bp->b_iocout.b_flags = BSCRXTO; /* read timeout */
bp->b_mode = BSC_IDLE; /* error state, idle mode */
bp->b_hlflgs |= BSC_ERR;
bp->b_state = START;
wakeup ((caddr_t)bp->b_buffer);
goto done;
}
#ifdef NBSM
}
#endif
if ((!bp->b_alenb) || (--(bp->b_alarm) > 0)) {
/* alarm has yet to go off - sleep */
goto out;
}
bp->b_alenb = 0; /* disable alarm */
switch (st->s_type) { /* what to do depends on state */
case 's': /* send time out ... modem dead! */
bp->b_state = XTO; /* set state to xmit timeout */
break;
case 'r': /* receive timeout - take s_next */
if (bp->b_trace) /* if tracing, show rcv t/o */
bsctr ((dev_t)dev, C_RTO, 'c'); /* reCv'd TimeOut */
bp->b_state = st->s_next; /* timeout state */
bp->b_class1 = C_RTO; /* timeout data class */
bp->b_rclptr = 0; /* reset receiver */
brxres((dev_t)dev);
break;
case 'd': /* function delay */
bp->b_alarm = -100; /* indicate second time through */
break;
default:
panic ("bsc: timeout in unknown state!\n");
break;
}
done:
bscpsm ((dev_t)dev); /* restart processing */
out: /* set up next call to bscpto */
timeout (bscpto, dev, PSMTICK); /* timeout again */
}
/*
* Compare two strings -- return zero if match, non-zero if fail
*/
bsccmp(s1,s2)
register char *s1, *s2;
{
while (*s1)
if (*s1++ != *s2++)
return 1;
return (int) *s2;
}
/*
* NAME
* btxtrc - trace tx data
* SYNOPSIS
* btxtrc(dev,xlptr,state)
* dev_t dev;
* int state;
* struct xlist *xlptr;
* ALGORITHM
* For each transmit list element, call bsctr to trace the
* transmit data (type is 'x'; supply xlen and xptr)
*/
btxtrc(dev,xlptr,state)
register dev_t dev;
register int state;
register struct xlist *xlptr;
{
while (xlptr->xptr) {
bsctr(dev,state,'x',(short)xlptr->xnum,xlptr->xptr);
++xlptr;
}
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.