148664Sbostic /*-
2*62391Sbostic * Copyright (c) 1985, 1993
3*62391Sbostic * The Regents of the University of California. All rights reserved.
448664Sbostic *
548664Sbostic * %sccs.include.proprietary.c%
648664Sbostic */
748664Sbostic
813663Ssam #ifndef lint
9*62391Sbostic static char sccsid[] = "@(#)pk0.c 8.1 (Berkeley) 06/06/93";
1048664Sbostic #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 */
pkcntl(c,pk)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
pkaccept(pk)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*/
pkread(pk,ibuf,icount)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*/
pkwrite(pk,ibuf,icount)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
pksack(pk)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
pkoutput(pk)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*/
pkclose(pk)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
pkreset(pk)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
bzero(s,n)55517836Sralph bzero(s,n)
55613663Ssam register char *s;
55713663Ssam register n;
55813663Ssam {
55913663Ssam while (n--)
56013663Ssam *s++ = 0;
56113663Ssam }
56217836Sralph #endif !BSD4_2
56313663Ssam
pksize(n)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