1 /*-
2 * Copyright (c) 1985, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * %sccs.include.proprietary.c%
6 */
7
8 #ifndef lint
9 static char sccsid[] = "@(#)pk0.c 8.1 (Berkeley) 06/06/93";
10 #endif /* not lint */
11
12 #include "uucp.h"
13 #include "pk.h"
14
15 /*
16 * packet driver
17 */
18
19 char next[8] = { 1, 2, 3, 4, 5, 6, 7, 0}; /* packet sequence numbers */
20 char mask[8] = { 1, 2, 4, 010, 020, 040, 0100, 0200 };
21
22 struct pack *pklines[NPLINES];
23
24 int Reacks;
25
26 #define PKRTIME 4
27 #define PKWTIME 4
28 #define PKRSKEW 3
29 #define PKWSKEW 2
30 extern int pktimeout, pktimeskew, Ntimeout;
31
32 /*
33 * receive control messages
34 */
pkcntl(c,pk)35 pkcntl(c, pk)
36 register struct pack *pk;
37 {
38 register cntl, val;
39
40 val = c & MOD8;
41 cntl = (c>>3) & MOD8;
42
43 if (!ISCNTL(c)) {
44 logent("PK0", "not cntl");
45 return;
46 }
47
48 switch(cntl) {
49 case INITB:
50 val++;
51 pk->p_xsize = pksizes[val];
52 pk->p_lpsize = val;
53 pk->p_bits = 1;
54 if (pk->p_state & LIVE) {
55 pk->p_msg |= M_INITC;
56 break;
57 }
58 pk->p_state |= INITb;
59 if ((pk->p_state & INITa)==0) {
60 break;
61 }
62 pk->p_rmsg &= ~M_INITA;
63 pk->p_msg |= M_INITC;
64 break;
65
66 case INITC:
67 if ((pk->p_state&INITab)==INITab) {
68 pk->p_state = LIVE;
69 pk->p_rmsg &= ~M_INITB;
70 } else
71 pk->p_msg |= M_INITB;
72 if (val)
73 pk->p_swindow = val;
74 break;
75 case INITA:
76 if (val == 0 && pk->p_state&LIVE) {
77 logent("PK0", "alloc change not implemented");
78 break;
79 }
80 if (val) {
81 pk->p_state |= INITa;
82 pk->p_msg |= M_INITB;
83 pk->p_rmsg |= M_INITB;
84 pk->p_swindow = val;
85 }
86 break;
87 case RJ:
88 pk->p_state |= RXMIT;
89 pk->p_msg |= M_RR;
90 pk->p_rpr = val;
91 (void) pksack(pk);
92 break;
93 case RR:
94 pk->p_rpr = val;
95 if (pk->p_rpr == pk->p_ps) {
96 DEBUG(9, "Reack count is %d\n", ++Reacks);
97 if (Reacks >= 4) {
98 DEBUG(6, "Reack overflow on %d\n", val);
99 pk->p_state |= RXMIT;
100 pk->p_msg |= M_RR;
101 Reacks = 0;
102 }
103 } else {
104 Reacks = 0;
105 (void) pksack(pk);
106 }
107 break;
108 case SRJ:
109 logent("PK0", "srj not implemented");
110 break;
111 case CLOSE:
112 pk->p_state = DOWN+RCLOSE;
113 return;
114 }
115 if (pk->p_msg)
116 pkoutput(pk);
117 }
118
pkaccept(pk)119 pkaccept(pk)
120 register struct pack *pk;
121 {
122 register x, seq;
123 char m, cntl, *p, imask, **bp;
124 int bad, accept, skip, t, cc;
125 unsigned short sum;
126
127 bad = accept = skip = 0;
128 /*
129 * wait for input
130 */
131 x = next[pk->p_pr];
132 while ((imask=pk->p_imap) == 0 && pk->p_rcount == 0) {
133 pkgetpack(pk);
134 }
135 pk->p_imap = 0;
136
137 /*
138 * determine input window in m.
139 */
140 t = (~(-1<<(int)(pk->p_rwindow))) <<x;
141 m = t;
142 m |= t>>8;
143
144 /*
145 * mark newly accepted input buffers
146 */
147 for(x=0; x<8; x++) {
148 if ((imask & mask[x]) == 0)
149 continue;
150
151 if (((cntl=pk->p_is[x])&0200) == 0) {
152 bad++;
153 free:
154 bp = (char **)pk->p_ib[x];
155 *bp = (char *)pk->p_ipool;
156 pk->p_ipool = bp;
157 pk->p_is[x] = 0;
158 continue;
159 }
160
161 pk->p_is[x] = ~(B_COPY+B_MARK);
162 sum = (unsigned)chksum(pk->p_ib[x], pk->p_rsize) ^ (unsigned)(cntl&0377);
163 sum += pk->p_isum[x];
164 if (sum == CHECK) {
165 seq = (cntl>>3) & MOD8;
166 if (m & mask[seq]) {
167 if (pk->p_is[seq] & (B_COPY | B_MARK)) {
168 dup:
169 pk->p_msg |= M_RR;
170 skip++;
171 goto free;
172 }
173 if (x != seq) {
174 p = pk->p_ib[x];
175 pk->p_ib[x] = pk->p_ib[seq];
176 pk->p_is[x] = pk->p_is[seq];
177 pk->p_ib[seq] = p;
178 }
179 pk->p_is[seq] = B_MARK;
180 accept++;
181 cc = 0;
182 if (cntl&B_SHORT) {
183 pk->p_is[seq] = B_MARK+B_SHORT;
184 p = pk->p_ib[seq];
185 cc = (unsigned)*p++ & 0377;
186 if (cc & 0200) {
187 cc &= 0177;
188 cc |= *p << 7;
189 }
190 }
191 pk->p_isum[seq] = pk->p_rsize - cc;
192 } else {
193 goto dup;
194 }
195 } else {
196 bad++;
197 goto free;
198 }
199 }
200
201 /*
202 * scan window again turning marked buffers into
203 * COPY buffers and looking for missing sequence
204 * numbers.
205 */
206 accept = 0;
207 t = -1;
208 for(x=next[pk->p_pr]; m & mask[x]; x = next[x]) {
209 if (pk->p_is[x] & B_MARK)
210 pk->p_is[x] |= B_COPY;
211
212 if (pk->p_is[x] & B_COPY) {
213 if (t >= 0) {
214 bp = (char **)pk->p_ib[x];
215 *bp = (char *)pk->p_ipool;
216 pk->p_ipool = bp;
217 pk->p_is[x] = 0;
218 skip++;
219 } else
220 accept++;
221 } else {
222 if (t<0)
223 t = x;
224 }
225 }
226
227 if (bad) {
228 pk->p_msg |= M_RJ;
229 }
230
231 if (skip) {
232 pk->p_msg |= M_RR;
233 }
234
235 pk->p_rcount = accept;
236 return accept;
237 }
238
239 /*ARGSUSED*/
pkread(pk,ibuf,icount)240 pkread(pk, ibuf, icount)
241 register struct pack *pk;
242 char *ibuf;
243 int icount;
244 {
245 register x;
246 int is, cc, xfr, count;
247 char *cp, **bp;
248
249 xfr = 0;
250 count = 0;
251 pktimeout = PKRTIME;
252 pktimeskew = PKRSKEW;
253 Ntimeout = 0;
254 while (pkaccept(pk) == 0)
255 ;
256
257 while (icount) {
258 x = next[pk->p_pr];
259 is = pk->p_is[x];
260
261 if (is & B_COPY) {
262 cc = MIN(pk->p_isum[x], icount);
263 if (cc==0 && xfr) {
264 break;
265 }
266 if (is & B_RESID)
267 cp = pk->p_rptr;
268 else {
269 cp = pk->p_ib[x];
270 if (is & B_SHORT) {
271 if (*cp++ & 0200)
272 cp++;
273 }
274 }
275 bcopy(cp, ibuf, cc);
276 ibuf += cc;
277 icount -= cc;
278 count += cc;
279 xfr++;
280 pk->p_isum[x] -= cc;
281 if (pk->p_isum[x] == 0) {
282 pk->p_pr = x;
283 bp = (char **)pk->p_ib[x];
284 *bp = (char *)pk->p_ipool;
285 pk->p_ipool = bp;
286 pk->p_is[x] = 0;
287 pk->p_rcount--;
288 pk->p_msg |= M_RR;
289 } else {
290 pk->p_rptr = cp+cc;
291 pk->p_is[x] |= B_RESID;
292 }
293 if (cc==0)
294 break;
295 } else
296 break;
297 }
298 pkoutput(pk);
299 return count;
300 }
301
302 /*ARGSUSED*/
pkwrite(pk,ibuf,icount)303 pkwrite(pk, ibuf, icount)
304 register struct pack *pk;
305 char *ibuf;
306 int icount;
307 {
308 register x;
309 int partial;
310 caddr_t cp;
311 int cc, fc, count;
312
313 if (pk->p_state&DOWN || !pk->p_state&LIVE) {
314 return -1;
315 }
316
317 pktimeout = PKWTIME;
318 pktimeskew = PKWSKEW;
319 Ntimeout = 0;
320 count = icount;
321 do {
322 while (pk->p_xcount>=pk->p_swindow) {
323 pkoutput(pk);
324 pkgetpack(pk);
325 }
326 x = next[pk->p_pscopy];
327 while (pk->p_os[x]!=B_NULL) {
328 pkgetpack(pk);
329 }
330 pk->p_os[x] = B_MARK;
331 pk->p_pscopy = x;
332 pk->p_xcount++;
333
334 cp = pk->p_ob[x] = malloc((unsigned)pk->p_xsize);
335 partial = 0;
336 if ((int)icount < pk->p_xsize) {
337 cc = icount;
338 fc = pk->p_xsize - cc;
339 *cp = fc&0177;
340 if (fc > 127) {
341 *cp++ |= 0200;
342 *cp++ = fc>>7;
343 } else
344 cp++;
345 partial = B_SHORT;
346 } else
347 cc = pk->p_xsize;
348 bcopy(ibuf, cp, cc);
349 ibuf += cc;
350 icount -= cc;
351 pk->p_osum[x] = chksum(pk->p_ob[x], pk->p_xsize);
352 pk->p_os[x] = B_READY+partial;
353 pkoutput(pk);
354 } while (icount);
355
356 return count;
357 }
358
pksack(pk)359 pksack(pk)
360 register struct pack *pk;
361 {
362 register x, i;
363
364 i = 0;
365 for(x=pk->p_ps; x!=pk->p_rpr; ) {
366 x = next[x];
367 if (pk->p_os[x]&B_SENT) {
368 i++;
369 pk->p_os[x] = B_NULL;
370 pk->p_state &= ~WAITO;
371 pk->p_xcount--;
372 free((char *)pk->p_ob[x]);
373 pk->p_ps = x;
374 }
375 }
376 return i;
377 }
378
pkoutput(pk)379 pkoutput(pk)
380 register struct pack *pk;
381 {
382 register x;
383 int i;
384 char bstate;
385
386 if (pk->p_obusy++) {
387 pk->p_obusy--;
388 return;
389 }
390
391 /*
392 * find seq number and buffer state
393 * of next output packet
394 */
395 if (pk->p_state&RXMIT) {
396 pk->p_nxtps = next[pk->p_rpr];
397 }
398 x = pk->p_nxtps;
399 bstate = pk->p_os[x];
400
401 /*
402 * Send control packet if indicated
403 */
404 if (pk->p_msg) {
405 if (pk->p_msg & ~M_RR || !(bstate&B_READY) ) {
406 x = pk->p_msg;
407 for(i=0; i<8; i++)
408 if (x&1)
409 break;
410 else
411 x >>= 1;
412 x = i;
413 x <<= 3;
414 switch(i) {
415 case CLOSE:
416 break;
417 case RJ:
418 case RR:
419 x += pk->p_pr;
420 break;
421 case SRJ:
422 break;
423 case INITB:
424 x += pksize(pk->p_rsize);
425 break;
426 case INITC:
427 x += pk->p_rwindow;
428 break;
429 case INITA:
430 x += pk->p_rwindow;
431 break;
432 }
433
434 pk->p_msg &= ~mask[i];
435 pkxstart(pk, x, -1);
436 goto out;
437 }
438 }
439
440
441 /*
442 * Don't send data packets if line is marked dead.
443 */
444 if (pk->p_state&DOWN) {
445 goto out;
446 }
447 /*
448 * Start transmission (or retransmission) of data packets.
449 */
450 if (bstate & (B_READY|B_SENT)) {
451 char seq;
452
453 bstate |= B_SENT;
454 seq = x;
455 pk->p_nxtps = next[x];
456
457 x = 0200+pk->p_pr+(seq<<3);
458 if (bstate & B_SHORT)
459 x |= 0100;
460 pkxstart(pk, x, seq);
461 pk->p_os[seq] = bstate;
462 pk->p_state &= ~RXMIT;
463 goto out;
464 }
465 /*
466 * enable timeout if there's nothing to send
467 * and transmission buffers are languishing
468 */
469 if (pk->p_xcount) {
470 pk->p_state |= WAITO;
471 } else
472 pk->p_state &= ~WAITO;
473 out:
474 pk->p_obusy = 0;
475 }
476
477 /*
478 * shut down line by
479 * ignoring new input
480 * letting output drain
481 * releasing space and turning off line discipline
482 */
483 /*ARGSUSED*/
pkclose(pk)484 pkclose(pk)
485 register struct pack *pk;
486 {
487 register i;
488 char **bp;
489 int rcheck = 0;
490
491 pk->p_state |= DRAINO;
492
493 /*
494 * try to flush output
495 */
496 i = 0;
497 while (pk->p_xcount && pk->p_state&LIVE) {
498 if (pk->p_state&(RCLOSE+DOWN) || ++i > 2)
499 break;
500 pkoutput(pk);
501 }
502 pk->p_state |= DOWN;
503
504 /*
505 * try to exchange CLOSE messages
506 */
507 i = 0;
508 while ((pk->p_state&RCLOSE)==0 && i<2) {
509 pk->p_msg = M_CLOSE;
510 pkoutput(pk);
511 i++;
512 }
513
514 for(i=0;i<NPLINES;i++)
515 if (pklines[i]==pk) {
516 pklines[i] = NULL;
517 }
518
519 /*
520 * free space
521 */
522 rcheck = 0;
523 for (i=0;i<8;i++) {
524 if (pk->p_os[i] != B_NULL) {
525 free((char *)pk->p_ob[i]);
526 pk->p_xcount--;
527 }
528 if (pk->p_is[i] != B_NULL) {
529 free((char *)pk->p_ib[i]);
530 rcheck++;
531 }
532 }
533 while (pk->p_ipool != NULL) {
534 bp = pk->p_ipool;
535 pk->p_ipool = (char **)*bp;
536 rcheck++;
537 free((char *)bp);
538 }
539 if (rcheck != pk->p_rwindow) {
540 syslog(LOG_WARNING, "%s: pk0: rc %d rw %d", Rmtname, rcheck,
541 pk->p_rwindow);
542 }
543 free((char *)pk);
544 }
545
pkreset(pk)546 pkreset(pk)
547 register struct pack *pk;
548 {
549
550 pk->p_ps = pk->p_pr = pk->p_rpr = 0;
551 pk->p_nxtps = 1;
552 }
553
554 #ifndef BSD4_2
bzero(s,n)555 bzero(s,n)
556 register char *s;
557 register n;
558 {
559 while (n--)
560 *s++ = 0;
561 }
562 #endif !BSD4_2
563
pksize(n)564 pksize(n)
565 register n;
566 {
567 register k;
568
569 n >>= 5;
570 for(k=0; n >>= 1; k++)
571 ;
572 return k;
573 }
574