1*48664Sbostic /*- 2*48664Sbostic * Copyright (c) 1985 The Regents of the University of California. 3*48664Sbostic * All rights reserved. 4*48664Sbostic * 5*48664Sbostic * %sccs.include.proprietary.c% 6*48664Sbostic */ 7*48664Sbostic 813663Ssam #ifndef lint 9*48664Sbostic static char sccsid[] = "@(#)pk0.c 5.10 (Berkeley) 04/24/91"; 10*48664Sbostic #endif /* not lint */ 1113663Ssam 1218620Sralph #include "uucp.h" 1313663Ssam #include "pk.h" 1413663Ssam 1513663Ssam /* 1613663Ssam * packet driver 1713663Ssam */ 1813663Ssam 1917836Sralph char next[8] = { 1, 2, 3, 4, 5, 6, 7, 0}; /* packet sequence numbers */ 2017836Sralph char mask[8] = { 1, 2, 4, 010, 020, 040, 0100, 0200 }; 2113663Ssam 2213663Ssam struct pack *pklines[NPLINES]; 2313663Ssam 2428888Sbloom int Reacks; 2525706Sbloom 2628888Sbloom #define PKRTIME 4 2728888Sbloom #define PKWTIME 4 2828888Sbloom #define PKRSKEW 3 2928888Sbloom #define PKWSKEW 2 3028888Sbloom extern int pktimeout, pktimeskew, Ntimeout; 3128888Sbloom 3213663Ssam /* 3313663Ssam * receive control messages 3413663Ssam */ 3513663Ssam pkcntl(c, pk) 3613663Ssam register struct pack *pk; 3713663Ssam { 3817836Sralph register cntl, val; 3913663Ssam 4013663Ssam val = c & MOD8; 4113663Ssam cntl = (c>>3) & MOD8; 4213663Ssam 4317836Sralph if (!ISCNTL(c)) { 4417836Sralph logent("PK0", "not cntl"); 4513663Ssam return; 4613663Ssam } 4713663Ssam 4813663Ssam switch(cntl) { 4913663Ssam case INITB: 5013663Ssam val++; 5113663Ssam pk->p_xsize = pksizes[val]; 5213663Ssam pk->p_lpsize = val; 5317836Sralph pk->p_bits = 1; 5413663Ssam if (pk->p_state & LIVE) { 5513663Ssam pk->p_msg |= M_INITC; 5613663Ssam break; 5713663Ssam } 5813663Ssam pk->p_state |= INITb; 5913663Ssam if ((pk->p_state & INITa)==0) { 6013663Ssam break; 6113663Ssam } 6213663Ssam pk->p_rmsg &= ~M_INITA; 6313663Ssam pk->p_msg |= M_INITC; 6413663Ssam break; 6513663Ssam 6613663Ssam case INITC: 6713663Ssam if ((pk->p_state&INITab)==INITab) { 6813663Ssam pk->p_state = LIVE; 6913663Ssam pk->p_rmsg &= ~M_INITB; 7013663Ssam } else 7113663Ssam pk->p_msg |= M_INITB; 7213663Ssam if (val) 7313663Ssam pk->p_swindow = val; 7413663Ssam break; 7513663Ssam case INITA: 7617836Sralph if (val == 0 && pk->p_state&LIVE) { 7717836Sralph logent("PK0", "alloc change not implemented"); 7813663Ssam break; 7913663Ssam } 8013663Ssam if (val) { 8113663Ssam pk->p_state |= INITa; 8213663Ssam pk->p_msg |= M_INITB; 8313663Ssam pk->p_rmsg |= M_INITB; 8413663Ssam pk->p_swindow = val; 8513663Ssam } 8613663Ssam break; 8713663Ssam case RJ: 8813663Ssam pk->p_state |= RXMIT; 8913663Ssam pk->p_msg |= M_RR; 9013663Ssam pk->p_rpr = val; 9117836Sralph (void) pksack(pk); 9213663Ssam break; 9328888Sbloom case RR: 9428888Sbloom pk->p_rpr = val; 9528888Sbloom if (pk->p_rpr == pk->p_ps) { 9628888Sbloom DEBUG(9, "Reack count is %d\n", ++Reacks); 9728888Sbloom if (Reacks >= 4) { 9828888Sbloom DEBUG(6, "Reack overflow on %d\n", val); 9928888Sbloom pk->p_state |= RXMIT; 10028888Sbloom pk->p_msg |= M_RR; 10128888Sbloom Reacks = 0; 10228888Sbloom } 10328888Sbloom } else { 10428888Sbloom Reacks = 0; 10528888Sbloom (void) pksack(pk); 10628888Sbloom } 10728888Sbloom break; 10813663Ssam case SRJ: 10917836Sralph logent("PK0", "srj not implemented"); 11013663Ssam break; 11113663Ssam case CLOSE: 11213663Ssam pk->p_state = DOWN+RCLOSE; 11313663Ssam return; 11413663Ssam } 11513663Ssam if (pk->p_msg) 11613663Ssam pkoutput(pk); 11713663Ssam } 11813663Ssam 11913663Ssam pkaccept(pk) 12013663Ssam register struct pack *pk; 12113663Ssam { 12217836Sralph register x, seq; 12317836Sralph char m, cntl, *p, imask, **bp; 12417836Sralph int bad, accept, skip, t, cc; 12517836Sralph unsigned short sum; 12613663Ssam 12713663Ssam bad = accept = skip = 0; 12813663Ssam /* 12913663Ssam * wait for input 13013663Ssam */ 13113663Ssam x = next[pk->p_pr]; 13217836Sralph while ((imask=pk->p_imap) == 0 && pk->p_rcount == 0) { 13317836Sralph pkgetpack(pk); 13413663Ssam } 13513663Ssam pk->p_imap = 0; 13613663Ssam 13713663Ssam /* 13813663Ssam * determine input window in m. 13913663Ssam */ 14013663Ssam t = (~(-1<<(int)(pk->p_rwindow))) <<x; 14113663Ssam m = t; 14213663Ssam m |= t>>8; 14313663Ssam 14413663Ssam /* 14513663Ssam * mark newly accepted input buffers 14613663Ssam */ 14713663Ssam for(x=0; x<8; x++) { 14813663Ssam if ((imask & mask[x]) == 0) 14913663Ssam continue; 15013663Ssam 15117836Sralph if (((cntl=pk->p_is[x])&0200) == 0) { 15213663Ssam bad++; 15313663Ssam free: 15413663Ssam bp = (char **)pk->p_ib[x]; 15513663Ssam *bp = (char *)pk->p_ipool; 15613663Ssam pk->p_ipool = bp; 15713663Ssam pk->p_is[x] = 0; 15813663Ssam continue; 15913663Ssam } 16013663Ssam 16113663Ssam pk->p_is[x] = ~(B_COPY+B_MARK); 16213663Ssam sum = (unsigned)chksum(pk->p_ib[x], pk->p_rsize) ^ (unsigned)(cntl&0377); 16313663Ssam sum += pk->p_isum[x]; 16413663Ssam if (sum == CHECK) { 16513663Ssam seq = (cntl>>3) & MOD8; 16613663Ssam if (m & mask[seq]) { 16713663Ssam if (pk->p_is[seq] & (B_COPY | B_MARK)) { 16813663Ssam dup: 16913663Ssam pk->p_msg |= M_RR; 17013663Ssam skip++; 17113663Ssam goto free; 17213663Ssam } 17313663Ssam if (x != seq) { 17413663Ssam p = pk->p_ib[x]; 17513663Ssam pk->p_ib[x] = pk->p_ib[seq]; 17613663Ssam pk->p_is[x] = pk->p_is[seq]; 17713663Ssam pk->p_ib[seq] = p; 17813663Ssam } 17913663Ssam pk->p_is[seq] = B_MARK; 18013663Ssam accept++; 18113663Ssam cc = 0; 18213663Ssam if (cntl&B_SHORT) { 18313663Ssam pk->p_is[seq] = B_MARK+B_SHORT; 18413663Ssam p = pk->p_ib[seq]; 18513663Ssam cc = (unsigned)*p++ & 0377; 18613663Ssam if (cc & 0200) { 18713663Ssam cc &= 0177; 18813663Ssam cc |= *p << 7; 18913663Ssam } 19013663Ssam } 19113663Ssam pk->p_isum[seq] = pk->p_rsize - cc; 19213663Ssam } else { 19313663Ssam goto dup; 19413663Ssam } 19513663Ssam } else { 19613663Ssam bad++; 19713663Ssam goto free; 19813663Ssam } 19913663Ssam } 20013663Ssam 20113663Ssam /* 20213663Ssam * scan window again turning marked buffers into 20313663Ssam * COPY buffers and looking for missing sequence 20413663Ssam * numbers. 20513663Ssam */ 20613663Ssam accept = 0; 20717836Sralph t = -1; 20817836Sralph for(x=next[pk->p_pr]; m & mask[x]; x = next[x]) { 20913663Ssam if (pk->p_is[x] & B_MARK) 21013663Ssam pk->p_is[x] |= B_COPY; 21117836Sralph 21213663Ssam if (pk->p_is[x] & B_COPY) { 21313663Ssam if (t >= 0) { 21413663Ssam bp = (char **)pk->p_ib[x]; 21513663Ssam *bp = (char *)pk->p_ipool; 21613663Ssam pk->p_ipool = bp; 21713663Ssam pk->p_is[x] = 0; 21813663Ssam skip++; 21917836Sralph } else 22013663Ssam accept++; 22113663Ssam } else { 22213663Ssam if (t<0) 22313663Ssam t = x; 22413663Ssam } 22513663Ssam } 22613663Ssam 22713663Ssam if (bad) { 22813663Ssam pk->p_msg |= M_RJ; 22913663Ssam } 23013663Ssam 23113663Ssam if (skip) { 23213663Ssam pk->p_msg |= M_RR; 23313663Ssam } 23413663Ssam 23513663Ssam pk->p_rcount = accept; 23617836Sralph return accept; 23713663Ssam } 23813663Ssam 23917836Sralph /*ARGSUSED*/ 24023614Sbloom pkread(pk, ibuf, icount) 24123614Sbloom register struct pack *pk; 24223614Sbloom char *ibuf; 24317836Sralph int icount; 24413663Ssam { 24517836Sralph register x; 24617836Sralph int is, cc, xfr, count; 24717836Sralph char *cp, **bp; 24813663Ssam 24913663Ssam xfr = 0; 25013663Ssam count = 0; 25128888Sbloom pktimeout = PKRTIME; 25228888Sbloom pktimeskew = PKRSKEW; 25325706Sbloom Ntimeout = 0; 25417836Sralph while (pkaccept(pk) == 0) 25517836Sralph ; 25613663Ssam 25717836Sralph while (icount) { 25813663Ssam x = next[pk->p_pr]; 25913663Ssam is = pk->p_is[x]; 26013663Ssam 26113663Ssam if (is & B_COPY) { 26217836Sralph cc = MIN(pk->p_isum[x], icount); 26313663Ssam if (cc==0 && xfr) { 26413663Ssam break; 26513663Ssam } 26613663Ssam if (is & B_RESID) 26713663Ssam cp = pk->p_rptr; 26813663Ssam else { 26913663Ssam cp = pk->p_ib[x]; 27013663Ssam if (is & B_SHORT) { 27113663Ssam if (*cp++ & 0200) 27213663Ssam cp++; 27313663Ssam } 27413663Ssam } 27533955Srick bcopy(cp, ibuf, cc); 27617836Sralph ibuf += cc; 27717836Sralph icount -= cc; 27813663Ssam count += cc; 27913663Ssam xfr++; 28013663Ssam pk->p_isum[x] -= cc; 28113663Ssam if (pk->p_isum[x] == 0) { 28213663Ssam pk->p_pr = x; 28313663Ssam bp = (char **)pk->p_ib[x]; 28413663Ssam *bp = (char *)pk->p_ipool; 28513663Ssam pk->p_ipool = bp; 28613663Ssam pk->p_is[x] = 0; 28713663Ssam pk->p_rcount--; 28813663Ssam pk->p_msg |= M_RR; 28913663Ssam } else { 29013663Ssam pk->p_rptr = cp+cc; 29113663Ssam pk->p_is[x] |= B_RESID; 29213663Ssam } 29313663Ssam if (cc==0) 29413663Ssam break; 29513663Ssam } else 29613663Ssam break; 29713663Ssam } 29813663Ssam pkoutput(pk); 29917836Sralph return count; 30013663Ssam } 30113663Ssam 30217836Sralph /*ARGSUSED*/ 30323614Sbloom pkwrite(pk, ibuf, icount) 30423614Sbloom register struct pack *pk; 30517836Sralph char *ibuf; 30617836Sralph int icount; 30713663Ssam { 30817836Sralph register x; 30917836Sralph int partial; 31017836Sralph caddr_t cp; 31117836Sralph int cc, fc, count; 31213663Ssam 31313663Ssam if (pk->p_state&DOWN || !pk->p_state&LIVE) { 31417836Sralph return -1; 31513663Ssam } 31613663Ssam 31728888Sbloom pktimeout = PKWTIME; 31828888Sbloom pktimeskew = PKWSKEW; 31925706Sbloom Ntimeout = 0; 32017836Sralph count = icount; 32113663Ssam do { 32213663Ssam while (pk->p_xcount>=pk->p_swindow) { 32313663Ssam pkoutput(pk); 32417836Sralph pkgetpack(pk); 32513663Ssam } 32613663Ssam x = next[pk->p_pscopy]; 32713663Ssam while (pk->p_os[x]!=B_NULL) { 32817836Sralph pkgetpack(pk); 32913663Ssam } 33013663Ssam pk->p_os[x] = B_MARK; 33113663Ssam pk->p_pscopy = x; 33213663Ssam pk->p_xcount++; 33313663Ssam 33417836Sralph cp = pk->p_ob[x] = malloc((unsigned)pk->p_xsize); 33513663Ssam partial = 0; 33617836Sralph if ((int)icount < pk->p_xsize) { 33717836Sralph cc = icount; 33813663Ssam fc = pk->p_xsize - cc; 33913663Ssam *cp = fc&0177; 34013663Ssam if (fc > 127) { 34113663Ssam *cp++ |= 0200; 34213663Ssam *cp++ = fc>>7; 34313663Ssam } else 34413663Ssam cp++; 34513663Ssam partial = B_SHORT; 34613663Ssam } else 34713663Ssam cc = pk->p_xsize; 34833955Srick bcopy(ibuf, cp, cc); 34917836Sralph ibuf += cc; 35017836Sralph icount -= cc; 35113663Ssam pk->p_osum[x] = chksum(pk->p_ob[x], pk->p_xsize); 35213663Ssam pk->p_os[x] = B_READY+partial; 35313663Ssam pkoutput(pk); 35417836Sralph } while (icount); 35513663Ssam 35617836Sralph return count; 35713663Ssam } 35813663Ssam 35913663Ssam pksack(pk) 36013663Ssam register struct pack *pk; 36113663Ssam { 36217836Sralph register x, i; 36313663Ssam 36413663Ssam i = 0; 36513663Ssam for(x=pk->p_ps; x!=pk->p_rpr; ) { 36613663Ssam x = next[x]; 36713663Ssam if (pk->p_os[x]&B_SENT) { 36813663Ssam i++; 36913663Ssam pk->p_os[x] = B_NULL; 37013663Ssam pk->p_state &= ~WAITO; 37113663Ssam pk->p_xcount--; 37217836Sralph free((char *)pk->p_ob[x]); 37313663Ssam pk->p_ps = x; 37413663Ssam } 37513663Ssam } 37617836Sralph return i; 37713663Ssam } 37813663Ssam 37913663Ssam pkoutput(pk) 38013663Ssam register struct pack *pk; 38113663Ssam { 38217836Sralph register x; 38317836Sralph int i; 38417836Sralph char bstate; 38513663Ssam 38617836Sralph if (pk->p_obusy++) { 38713663Ssam pk->p_obusy--; 38813663Ssam return; 38913663Ssam } 39013663Ssam 39113663Ssam /* 39213663Ssam * find seq number and buffer state 39313663Ssam * of next output packet 39413663Ssam */ 39513663Ssam if (pk->p_state&RXMIT) { 39613663Ssam pk->p_nxtps = next[pk->p_rpr]; 39713663Ssam } 39813663Ssam x = pk->p_nxtps; 39913663Ssam bstate = pk->p_os[x]; 40013663Ssam 40113663Ssam /* 40213663Ssam * Send control packet if indicated 40313663Ssam */ 40413663Ssam if (pk->p_msg) { 40513663Ssam if (pk->p_msg & ~M_RR || !(bstate&B_READY) ) { 40613663Ssam x = pk->p_msg; 40717836Sralph for(i=0; i<8; i++) 40813663Ssam if (x&1) 40917836Sralph break; 41017836Sralph else 41117836Sralph x >>= 1; 41213663Ssam x = i; 41313663Ssam x <<= 3; 41413663Ssam switch(i) { 41513663Ssam case CLOSE: 41613663Ssam break; 41713663Ssam case RJ: 41813663Ssam case RR: 41913663Ssam x += pk->p_pr; 42013663Ssam break; 42113663Ssam case SRJ: 42213663Ssam break; 42313663Ssam case INITB: 42413663Ssam x += pksize(pk->p_rsize); 42513663Ssam break; 42613663Ssam case INITC: 42713663Ssam x += pk->p_rwindow; 42813663Ssam break; 42913663Ssam case INITA: 43013663Ssam x += pk->p_rwindow; 43113663Ssam break; 43213663Ssam } 43313663Ssam 43413663Ssam pk->p_msg &= ~mask[i]; 43513663Ssam pkxstart(pk, x, -1); 43613663Ssam goto out; 43713663Ssam } 43813663Ssam } 43913663Ssam 44013663Ssam 44113663Ssam /* 44213663Ssam * Don't send data packets if line is marked dead. 44313663Ssam */ 44413663Ssam if (pk->p_state&DOWN) { 44513663Ssam goto out; 44613663Ssam } 44713663Ssam /* 44813663Ssam * Start transmission (or retransmission) of data packets. 44913663Ssam */ 45013663Ssam if (bstate & (B_READY|B_SENT)) { 45113663Ssam char seq; 45213663Ssam 45313663Ssam bstate |= B_SENT; 45413663Ssam seq = x; 45513663Ssam pk->p_nxtps = next[x]; 45613663Ssam 45713663Ssam x = 0200+pk->p_pr+(seq<<3); 45813663Ssam if (bstate & B_SHORT) 45913663Ssam x |= 0100; 46013663Ssam pkxstart(pk, x, seq); 46113663Ssam pk->p_os[seq] = bstate; 46213663Ssam pk->p_state &= ~RXMIT; 46313663Ssam goto out; 46413663Ssam } 46513663Ssam /* 46613663Ssam * enable timeout if there's nothing to send 46713663Ssam * and transmission buffers are languishing 46813663Ssam */ 46913663Ssam if (pk->p_xcount) { 47013663Ssam pk->p_state |= WAITO; 47113663Ssam } else 47213663Ssam pk->p_state &= ~WAITO; 47313663Ssam out: 47413663Ssam pk->p_obusy = 0; 47513663Ssam } 47613663Ssam 47713663Ssam /* 47813663Ssam * shut down line by 47913663Ssam * ignoring new input 48013663Ssam * letting output drain 48113663Ssam * releasing space and turning off line discipline 48213663Ssam */ 48317836Sralph /*ARGSUSED*/ 48423614Sbloom pkclose(pk) 48523614Sbloom register struct pack *pk; 48613663Ssam { 48718620Sralph register i; 48817836Sralph char **bp; 48918620Sralph int rcheck = 0; 49013663Ssam 49113663Ssam pk->p_state |= DRAINO; 49213663Ssam 49313663Ssam /* 49413663Ssam * try to flush output 49513663Ssam */ 49613663Ssam i = 0; 49713663Ssam while (pk->p_xcount && pk->p_state&LIVE) { 49813663Ssam if (pk->p_state&(RCLOSE+DOWN) || ++i > 2) 49913663Ssam break; 50013663Ssam pkoutput(pk); 50113663Ssam } 50213663Ssam pk->p_state |= DOWN; 50313663Ssam 50413663Ssam /* 50513663Ssam * try to exchange CLOSE messages 50613663Ssam */ 50713663Ssam i = 0; 50813663Ssam while ((pk->p_state&RCLOSE)==0 && i<2) { 50913663Ssam pk->p_msg = M_CLOSE; 51013663Ssam pkoutput(pk); 51113663Ssam i++; 51213663Ssam } 51313663Ssam 51413663Ssam for(i=0;i<NPLINES;i++) 51513663Ssam if (pklines[i]==pk) { 51613663Ssam pklines[i] = NULL; 51713663Ssam } 51813663Ssam 51913663Ssam /* 52013663Ssam * free space 52113663Ssam */ 52213663Ssam rcheck = 0; 52313663Ssam for (i=0;i<8;i++) { 52417836Sralph if (pk->p_os[i] != B_NULL) { 52517836Sralph free((char *)pk->p_ob[i]); 52613663Ssam pk->p_xcount--; 52713663Ssam } 52817836Sralph if (pk->p_is[i] != B_NULL) { 52917836Sralph free((char *)pk->p_ib[i]); 53013663Ssam rcheck++; 53113663Ssam } 53213663Ssam } 53313663Ssam while (pk->p_ipool != NULL) { 53413663Ssam bp = pk->p_ipool; 53513663Ssam pk->p_ipool = (char **)*bp; 53613663Ssam rcheck++; 53717836Sralph free((char *)bp); 53813663Ssam } 53917836Sralph if (rcheck != pk->p_rwindow) { 54033955Srick syslog(LOG_WARNING, "%s: pk0: rc %d rw %d", Rmtname, rcheck, 54133955Srick pk->p_rwindow); 54213663Ssam } 54317836Sralph free((char *)pk); 54413663Ssam } 54513663Ssam 54613663Ssam pkreset(pk) 54713663Ssam register struct pack *pk; 54813663Ssam { 54913663Ssam 55013663Ssam pk->p_ps = pk->p_pr = pk->p_rpr = 0; 55113663Ssam pk->p_nxtps = 1; 55213663Ssam } 55313663Ssam 55417836Sralph #ifndef BSD4_2 55517836Sralph bzero(s,n) 55613663Ssam register char *s; 55713663Ssam register n; 55813663Ssam { 55913663Ssam while (n--) 56013663Ssam *s++ = 0; 56113663Ssam } 56217836Sralph #endif !BSD4_2 56313663Ssam 56413663Ssam pksize(n) 56513663Ssam register n; 56613663Ssam { 56717836Sralph register k; 56813663Ssam 56913663Ssam n >>= 5; 57017836Sralph for(k=0; n >>= 1; k++) 57117836Sralph ; 57217836Sralph return k; 57313663Ssam } 574