+#define KERNEL 1
+#include "../h/pk.p"
+
+/*
+ * packet driver
+ */
+
+char next[8] ={ 1,2,3,4,5,6,7,0}; /* packet sequence numbers */
+char mask[8] ={ 1,2,4,010,020,040,0100,0200 };
+
+struct pack *pklines[NPLINES];
+
+
+/*
+ * receive control messages
+ */
+
+pkcntl(cntl, pk)
+register cntl;
+register struct pack *pk;
+{
+register val;
+register m;
+
+ val = cntl & MOD8;
+
+ if ( NOTCNTL(cntl) ) {
+ pkbadframe(pk);
+ return;
+ }
+
+ cntl >>= 3;
+ pk->p_state &= ~BADFRAME;
+ m = pk->p_msg;
+
+ switch(cntl) {
+
+ case INITB:
+ val++;
+ pk->p_xsize = pksizes[val];
+ pk->p_lpsize = val;
+ pk->p_bits = DTOM(pk->p_xsize);
+ if (pk->p_state & LIVE) {
+ pk->p_msg |= M_INITC;
+ break;
+ }
+ pk->p_state |= INITb;
+ if ((pk->p_state & INITa)==0) {
+ break;
+ }
+ pk->p_rmsg &= ~M_INITA;
+ pk->p_msg |= M_INITC;
+ break;
+
+ case INITC:
+ if ((pk->p_state&INITab)==INITab) {
+ pk->p_state = LIVE;
+ WAKEUP(&pk->p_state);
+ pk->p_rmsg &= ~(M_INITA|M_INITB);
+ } else
+ if ((pk->p_state&LIVE)==0)
+ pk->p_msg |= M_INITB;
+ if (val)
+ pk->p_swindow = val;
+ break;
+ case INITA:
+ if (val==0 && pk->p_state&LIVE) {
+ printf("alloc change\n");
+ break;
+ }
+ if (val) {
+ pk->p_state |= INITa;
+ pk->p_msg |= M_INITB;
+ pk->p_rmsg |= M_INITB;
+ pk->p_swindow = val;
+ }
+ break;
+ case RJ:
+ pk->p_state |= RXMIT;
+ pk->p_msg |= M_RR;
+ case RR:
+ pk->p_rpr = val;
+ if (pksack(pk)==0) {
+ WAKEUP(&pk->p_ps);
+ }
+ break;
+ case CLOSE:
+ pk->p_state = DOWN+RCLOSE;
+ pk->p_rmsg = 0;
+ WAKEUP(&pk->p_pr);
+ WAKEUP(&pk->p_ps);
+ WAKEUP(&pk->p_state);
+ return;
+ }
+ if (pk->p_msg==0)
+ pk->p_msg |= pk->p_rmsg;
+
+
+ if (m==0 && pk->p_msg)
+ pkoutput(pk);
+}
+
+
+/*
+ * Send RJ message on first framing error.
+ * Cleared by receiving a good frame
+ * (pkcntl or pkdata).
+ */
+pkbadframe(pk)
+register struct pack *pk;
+{
+ WAKEUP(&pk->p_pr);
+ if (pk->p_state & BADFRAME)
+ return;
+ pk->p_state |= BADFRAME;
+ pk->p_timer = 2;
+}
+
+
+
+
+/*
+ * Look at sequence numbers (mostly).
+ */
+pkaccept(pk)
+register struct pack *pk;
+{
+register x, seq;
+char m, cntl, *p, imask, **bp;
+int bad, accept, skip, s, t, cc;
+unsigned short sum;
+
+ bad = accept = skip = 0;
+ /*
+ * wait for input
+ */
+ LOCK;
+ x = next[pk->p_pr];
+ if((imask=pk->p_imap)==0 && pk->p_rcount==0) {
+ UNLOCK;
+ goto out;
+ }
+ pk->p_imap = 0;
+ UNLOCK;
+
+
+ /*
+ * determine input window in m.
+ */
+ t = (~(-1<<pk->p_rwindow)) <<x;
+ m = t;
+ m |= t>>8;
+
+
+ /*
+ * mark newly accepted input buffers
+ */
+ for(x=0; x<8; x++) {
+
+ if ((imask & mask[x]) == 0)
+ continue;
+
+ if (((cntl=pk->p_is[x])&0200)==0) {
+ bad++;
+free:
+ bp = (char **)pk->p_ib[x];
+ LOCK;
+ *bp = (char *)pk->p_ipool;
+ pk->p_ipool = bp;
+ pk->p_is[x] = 0;
+ UNLOCK;
+ continue;
+ }
+
+ pk->p_is[x] = ~(B_COPY+B_MARK);
+ sum = (unsigned)chksum(pk->p_ib[x], pk->p_rsize) ^ (unsigned)cntl;
+ sum += pk->p_isum[x];
+ if (sum == CHECK) {
+ seq = (cntl>>3) & MOD8;
+ if (m & mask[seq]) {
+ if (pk->p_is[seq] & (B_COPY | B_MARK)) {
+ dup:
+ skip++;
+ goto free;
+ }
+ if (x != seq) {
+ LOCK;
+ p = pk->p_ib[x];
+ pk->p_ib[x] = pk->p_ib[seq];
+ pk->p_is[x] = pk->p_is[seq];
+ pk->p_ib[seq] = p;
+ UNLOCK;
+ }
+ pk->p_is[seq] = B_MARK;
+ accept++;
+ cc = 0;
+ if (cntl&B_SHORT) {
+ pk->p_is[seq] = B_MARK+B_SHORT;
+ p = pk->p_ib[seq];
+ cc = (unsigned)*p++;
+ if (cc & 0200) {
+ cc &= 0177;
+ cc |= *p << 7;
+ }
+ }
+ pk->p_isum[seq] = pk->p_rsize - cc;
+ } else {
+ goto dup;
+ }
+ } else {
+ bad++;
+ goto free;
+ }
+ }
+
+ /*
+ * scan window again turning marked buffers into
+ * COPY buffers and looking for missing sequence
+ * numbers.
+ */
+ accept = 0;
+ for(x=next[pk->p_pr],t= -1; m & mask[x]; x = next[x]) {
+ if (pk->p_is[x] & B_MARK)
+ pk->p_is[x] |= B_COPY;
+ if (pk->p_is[x] & B_COPY) {
+ if (t >= 0) {
+ bp = (char **)pk->p_ib[x];
+ LOCK;
+ *bp = (char *)pk->p_ipool;
+ pk->p_ipool = bp;
+ pk->p_is[x] = 0;
+ UNLOCK;
+ skip++;
+ } else
+ accept++;
+ } else {
+ if (t<0)
+ t = x;
+ }
+ }
+
+ if (bad) {
+ pk->p_msg |= M_RJ;
+ } else
+
+ if (skip) {
+ pk->p_msg |= M_RR;
+ }
+
+ pk->p_rcount = accept;
+out:
+ if (pk->p_msg)
+ pkoutput(pk);
+ return(accept);
+}
+
+
+pkread(S)
+SDEF;
+{
+register struct pack *pk;
+register x,s;
+int is,cc,xfr,count;
+char *cp, **bp;
+
+ pk = PADDR;
+ xfr = 0;
+ count = -1;
+ while (pkaccept(pk) == 0) {
+ PKGETPKT(pk);
+ if (pk->p_state&DOWN) {
+ SETERROR;
+ goto out;
+ }
+ if (SLEEPNO) {
+ count++;
+ goto out;
+ }
+ SLEEP(&pk->p_pr, PKIPRI);
+ }
+ count = 0;
+
+
+ while (UCOUNT) {
+
+ x = next[pk->p_pr];
+ is = pk->p_is[x];
+
+ if (is & B_COPY) {
+ cc = MIN(pk->p_isum[x], UCOUNT);
+ if (cc==0 && xfr) {
+ break;
+ }
+ if (is & B_RESID)
+ cp = pk->p_rptr;
+ else {
+ cp = pk->p_ib[x];
+ if (is & B_SHORT) {
+ if (*cp++ & 0200)
+ *cp++;
+ }
+ }
+ IOMOVE(cp,cc,B_READ);
+ count += cc;
+ xfr++;
+ pk->p_isum[x] -= cc;
+ if (pk->p_isum[x] == 0) {
+ LOCK;
+ pk->p_pr = x;
+ bp = (char **)pk->p_ib[x];
+ *bp = (char *)pk->p_ipool;
+ pk->p_ipool = bp;
+ pk->p_is[x] = 0;
+ pk->p_rcount--;
+ UNLOCK;
+ pk->p_msg |= M_RR;
+ } else {
+ pk->p_rptr = cp+cc;
+ pk->p_is[x] |= B_RESID;
+ }
+ if (cc==0)
+ break;
+ } else
+ break;
+ }
+ pkoutput(pk);
+ if (SLEEPNO)
+ count = pk->p_rcount;
+out:
+ return(count);
+}
+
+
+
+
+pkwrite(S)
+SDEF;
+{
+register struct pack *pk;
+register x;
+int partial;
+caddr_t cp;
+int cc, s, fc, count;
+int pktimeout();
+
+ pk = PADDR;
+ if ((pk->p_state&LIVE)==0) {
+ down:
+ SIGNAL;
+ SETERROR;
+ return(-1);
+ }
+
+ count = UCOUNT;
+ do {
+ LOCK;
+ while (pk->p_xcount>=pk->p_swindow) {
+ pkoutput(pk);
+ PKGETPKT(pk);
+ SLEEP(&pk->p_ps,PKOPRI);
+ if (pk->p_state&DOWN)
+ goto down;
+ }
+ x = next[pk->p_pscopy];
+ while (pk->p_os[x]!=B_NULL) {
+ goto down;
+ }
+ pk->p_os[x] = B_MARK;
+ pk->p_pscopy = x;
+ pk->p_xcount++;
+ UNLOCK;
+
+ cp = pk->p_ob[x] = (char *)GETEPACK;
+ partial = 0;
+ if ((int)UCOUNT < pk->p_xsize) {
+ cc = UCOUNT;
+ fc = pk->p_xsize - cc;
+ *cp = fc&0177;
+ if (fc > 127) {
+ *cp++ |= 0200;
+ *cp++ = fc>>7;
+ } else
+ cp++;
+ partial = B_SHORT;
+ } else
+ cc = pk->p_xsize;
+ IOMOVE(cp,cc,B_WRITE);
+ pk->p_osum[x] = chksum(pk->p_ob[x], pk->p_xsize);
+ pk->p_os[x] = B_READY+partial;
+ pkoutput(pk);
+ } while (UCOUNT);
+
+ return(count-UCOUNT);
+}
+
+pksack(pk)
+register struct pack *pk;
+{
+register x, i;
+int s;
+
+ i = 0;
+ LOCK;
+ for(x=pk->p_ps; x!=pk->p_rpr; ) {
+ x = next[x];
+ if (pk->p_os[x]&B_SENT) {
+ i++;
+ FREEPACK(pk->p_ob[x], pk->p_bits);
+ pk->p_os[x] = B_NULL;
+ pk->p_state &= ~WAITO;
+ pk->p_xcount--;
+ pk->p_ps = x;
+ WAKEUP(&pk->p_ps);
+ }
+ }
+ UNLOCK;
+ return(i);
+}
+
+
+
+pkoutput(pk)
+register struct pack *pk;
+{
+register x;
+int s;
+char bstate;
+int i;
+SDEF;
+extern pkzot;
+
+ ISYSTEM;
+ LOCK;
+ if (OBUSY) {
+ UNLOCK;
+ return;
+ }
+
+
+ /*
+ * find seq number and buffer state
+ * of next output packet
+ */
+ if (pk->p_state&RXMIT) {
+ pk->p_nxtps = next[pk->p_rpr];
+ pk->p_state &= ~RXMIT;
+ }
+ x = pk->p_nxtps;
+ bstate = pk->p_os[x];
+
+
+ /*
+ * Send control packet if indicated
+ */
+ if (pk->p_msg) {
+ if (pk->p_msg & ~M_RR || !(bstate&B_READY) ) {
+ x = pk->p_msg;
+ for(i=0; i<8; i++)
+ if (x&1)
+ break; else
+ x >>= 1;
+ x = i;
+ x <<= 3;
+ switch(i) {
+ case CLOSE:
+ break;
+ case RJ:
+ case RR:
+ x += pk->p_pr;
+ break;
+ case SRJ:
+ break;
+ case INITB:
+ x += pksize(pk->p_rsize);
+ break;
+ case INITC:
+ x += pk->p_rwindow;
+ break;
+ case INITA:
+ x += pk->p_rwindow;
+ break;
+ }
+
+ pk->p_msg &= ~mask[i];
+ pkxstart(pk, x, -1);
+ goto out;
+ }
+ }
+
+
+ /*
+ * Don't send data packets if line is marked dead.
+ */
+ if (pk->p_state&DOWN || (pk->p_state&LIVE)==0) {
+ WAKEUP(&pk->p_ps);
+ goto out;
+ }
+ /*
+ * Start transmission (or retransmission) of data packets.
+ */
+ if (bstate & (B_READY|B_SENT)) {
+ char seq;
+
+ bstate |= B_SENT;
+ seq = x;
+ pk->p_nxtps = next[x];
+
+ x = 0200+pk->p_pr+(seq<<3);
+ if (bstate & B_SHORT)
+ x |= 0100;
+ pkxstart(pk, x, seq);
+ if (pk->p_os[seq])
+ pk->p_os[seq] = bstate;
+ pk->p_nout++;
+ goto out;
+ }
+ /*
+ * enable timeout if there's nothing to send
+ * and transmission buffers are languishing
+ */
+ if (pk->p_xcount) {
+ pk->p_timer = 10+pkzot;
+ pk->p_state |= WAITO;
+ } else
+ pk->p_state &= ~WAITO;
+ WAKEUP(&pk->p_ps);
+out:
+ pk->p_obusy = 0;
+ UNLOCK;
+}
+
+
+/*
+ * shut down line by
+ * ignoring new input
+ * letting output drain
+ * releasing space and turning off line discipline
+ */
+pkclose(S)
+SDEF;
+{
+register struct pack *pk;
+register i,s,rbits;
+char **bp;
+
+#define NTRIES 1
+
+ pk = PADDR;
+ pk->p_state |= DRAINO;
+
+
+ /*
+ * try to flush output
+ */
+ i = 0;
+ LOCK;
+ if (pklive(pk)==0) {
+ pk->p_state = DOWN;
+ UNLOCK;
+ goto final;
+ }
+ pk->p_timer = 2;
+ while (pk->p_xcount && pk->p_state&LIVE) {
+ if (pk->p_state&(RCLOSE+DOWN) || ++i > NTRIES)
+ break;
+ pkoutput(pk);
+ SLEEP(&pk->p_ps,PKOPRI);
+ }
+ pk->p_timer = 0;
+ pk->p_state |= DOWN;
+ UNLOCK;
+
+
+ /*
+ * try to exchange CLOSE messages
+ */
+ i = 0;
+ while ((pk->p_state&RCLOSE)==0 && i<NTRIES) {
+ pk->p_msg = M_CLOSE;
+ pk->p_timer = 2;
+ pkoutput(pk);
+ SLEEP(&pk->p_ps, PKOPRI);
+ i++;
+ }
+
+
+final:
+ TURNOFF;
+
+
+ /*
+ * free space
+ */
+ rbits = DTOM(pk->p_rsize);
+ for (i=0;i<8;i++) {
+ if (pk->p_os[i]!=B_NULL) {
+ FREEPACK(pk->p_ob[i],pk->p_bits);
+ pk->p_xcount--;
+ }
+ if (pk->p_is[i]!=B_NULL) {
+ FREEPACK(pk->p_ib[i],rbits);
+ }
+ }
+ LOCK;
+ while (pk->p_ipool != NULL) {
+ bp = pk->p_ipool;
+ pk->p_ipool = (char **)*bp;
+ FREEPACK((caddr_t)bp, rbits);
+ }
+ UNLOCK;
+ for(i=0;i<NPLINES;i++)
+ if (pklines[i]==pk) {
+ pklines[i] = NULL;
+ }
+ FREEPACK((caddr_t)pk, npbits);
+}
+
+
+
+pkreset(pk)
+register struct pack *pk;
+{
+
+ pk->p_ps = pk->p_pr = pk->p_rpr = 0;
+ pk->p_nxtps = 1;
+}
+
+chksum(s,n)
+register char *s;
+register n;
+{
+ register short sum;
+ register unsigned t;
+ register x;
+
+ sum = -1;
+ x = 0;
+
+ do {
+ if (sum<0) {
+ sum <<= 1;
+ sum++;
+ } else
+ sum <<= 1;
+ t = sum;
+ sum += (unsigned)*s++;
+ x += sum^n;
+ if ((unsigned)sum <= t) {
+ sum ^= x;
+ }
+ } while (--n > 0);
+
+ return(sum);
+}
+
+pkline(pk)
+register struct pack *pk;
+{
+register i;
+ for(i=0;i<NPLINES;i++) {
+ if (pklines[i]==pk)
+ return(i);
+ }
+ return(-i);
+}
+
+pkzero(s,n)
+register char *s;
+register n;
+{
+ while (n--)
+ *s++ = 0;
+}
+
+pksize(n)
+register n;
+{
+register k;
+
+ n >>= 5;
+ for(k=0; n >>= 1; k++);
+ return(k);
+}