BSD 4_2 release
[unix-history] / usr / src / usr.bin / uucp / pk0.c
CommitLineData
b0b08d43 1#ifndef lint
0f4556f1 2static char sccsid[] = "@(#)pk0.c 5.1 (Berkeley) 7/2/83";
b0b08d43
SL
3#endif
4
5extern char *malloc();
6
7#define USER 1
8#include <stdio.h>
9#ifdef SYSIII
10#include <sys/types.h>
11#endif
12#include "pk.p"
13#include <sys/param.h>
14#include "pk.h"
15#include <sys/buf.h>
16
17
18/*
19 * packet driver
20 */
21
22char next[8] ={ 1,2,3,4,5,6,7,0}; /* packet sequence numbers */
23char mask[8] ={ 1,2,4,010,020,040,0100,0200 };
24
25struct pack *pklines[NPLINES];
26
27/*
28 * Here are a couple of strange variables (rti!trt).
29 * pkactive is only incremented in pkopen.
30 * perhaps it should be decremented in pkclose?
31 * And pkdebug is set in gio.c but never used.
32 */
33int pkactive;
34int pkdebug;
35
36/*
37 * receive control messages
38 */
39pkcntl(c, pk)
40register struct pack *pk;
41{
42register cntl, val;
43
44 val = c & MOD8;
45 cntl = (c>>3) & MOD8;
46
47 if ( ! ISCNTL(c) ) {
48 fprintf(stderr, "not cntl\n");
49 return;
50 }
51
52 if (pk->p_mode & 02)
53 fprintf(stderr, "%o ",c);
54 switch(cntl) {
55
56 case INITB:
57 val++;
58 pk->p_xsize = pksizes[val];
59 pk->p_lpsize = val;
60 pk->p_bits = DTOM(pk->p_xsize);
61 if (pk->p_state & LIVE) {
62 pk->p_msg |= M_INITC;
63 break;
64 }
65 pk->p_state |= INITb;
66 if ((pk->p_state & INITa)==0) {
67 break;
68 }
69 pk->p_rmsg &= ~M_INITA;
70 pk->p_msg |= M_INITC;
71 break;
72
73 case INITC:
74 if ((pk->p_state&INITab)==INITab) {
75 pk->p_state = LIVE;
76 WAKEUP(&pk->p_state);
77 pk->p_rmsg &= ~M_INITB;
78 } else
79 pk->p_msg |= M_INITB;
80 if (val)
81 pk->p_swindow = val;
82 break;
83 case INITA:
84 if (val==0 && pk->p_state&LIVE) {
85 fprintf(stderr, "alloc change not implemented\n");
86 break;
87 }
88 if (val) {
89 pk->p_state |= INITa;
90 pk->p_msg |= M_INITB;
91 pk->p_rmsg |= M_INITB;
92 pk->p_swindow = val;
93 }
94 break;
95 case RJ:
96 pk->p_state |= RXMIT;
97 pk->p_msg |= M_RR;
98 case RR:
99 pk->p_rpr = val;
100 if (pksack(pk)==0) {
101 WAKEUP(&pk->p_ps);
102 }
103 break;
104 case SRJ:
105 fprintf(stderr, "srj not implemented\n");
106 break;
107 case CLOSE:
108 pk->p_state = DOWN+RCLOSE;
109 SIGNAL;
110 WAKEUP(&pk->p_pr);
111 WAKEUP(&pk->p_ps);
112 WAKEUP(&pk->p_state);
113 return;
114 }
115out:
116 if (pk->p_msg)
117 pkoutput(pk);
118}
119
120
121
122pkaccept(pk)
123register struct pack *pk;
124{
125register x,seq;
126char m, cntl, *p, imask, **bp;
127int bad,accept,skip,s,t,h,cc;
128unsigned short sum;
129
130
131 bad = accept = skip = 0;
132 /*
133 * wait for input
134 */
135 LOCK;
136 x = next[pk->p_pr];
137 while ((imask=pk->p_imap) == 0 && pk->p_rcount==0) {
138 PKGETPKT(pk);
139 SLEEP(&pk->p_pr, PKIPRI);
140 }
141 pk->p_imap = 0;
142 UNLOCK;
143
144
145 /*
146 * determine input window in m.
147 */
148 t = (~(-1<<(int)(pk->p_rwindow))) <<x;
149 m = t;
150 m |= t>>8;
151
152
153 /*
154 * mark newly accepted input buffers
155 */
156 for(x=0; x<8; x++) {
157
158 if ((imask & mask[x]) == 0)
159 continue;
160
161 if (((cntl=pk->p_is[x])&0200)==0) {
162 bad++;
163free:
164 bp = (char **)pk->p_ib[x];
165 LOCK;
166 *bp = (char *)pk->p_ipool;
167 pk->p_ipool = bp;
168 pk->p_is[x] = 0;
169 UNLOCK;
170 continue;
171 }
172
173 pk->p_is[x] = ~(B_COPY+B_MARK);
174 sum = (unsigned)chksum(pk->p_ib[x], pk->p_rsize) ^ (unsigned)(cntl&0377);
175 sum += pk->p_isum[x];
176 if (sum == CHECK) {
177 seq = (cntl>>3) & MOD8;
178 if (m & mask[seq]) {
179 if (pk->p_is[seq] & (B_COPY | B_MARK)) {
180 dup:
181 pk->p_msg |= M_RR;
182 skip++;
183 goto free;
184 }
185 if (x != seq) {
186 LOCK;
187 p = pk->p_ib[x];
188 pk->p_ib[x] = pk->p_ib[seq];
189 pk->p_is[x] = pk->p_is[seq];
190 pk->p_ib[seq] = p;
191 UNLOCK;
192 }
193 pk->p_is[seq] = B_MARK;
194 accept++;
195 cc = 0;
196 if (cntl&B_SHORT) {
197 pk->p_is[seq] = B_MARK+B_SHORT;
198 p = pk->p_ib[seq];
199 cc = (unsigned)*p++ & 0377;
200 if (cc & 0200) {
201 cc &= 0177;
202 cc |= *p << 7;
203 }
204 }
205 pk->p_isum[seq] = pk->p_rsize - cc;
206 } else {
207 goto dup;
208 }
209 } else {
210 bad++;
211 goto free;
212 }
213 }
214
215 /*
216 * scan window again turning marked buffers into
217 * COPY buffers and looking for missing sequence
218 * numbers.
219 */
220 accept = 0;
221 for(x=next[pk->p_pr],t=h= -1; m & mask[x]; x = next[x]) {
222 if (pk->p_is[x] & B_MARK)
223 pk->p_is[x] |= B_COPY;
224 /* hole code
225 if (pk->p_is[x] & B_COPY) {
226 if (h<0 && t>=0)
227 h = x;
228 } else {
229 if (t<0)
230 t = x;
231 }
232 */
233 if (pk->p_is[x] & B_COPY) {
234 if (t >= 0) {
235 bp = (char **)pk->p_ib[x];
236 LOCK;
237 *bp = (char *)pk->p_ipool;
238 pk->p_ipool = bp;
239 pk->p_is[x] = 0;
240 UNLOCK;
241 skip++;
242 } else
243 accept++;
244 } else {
245 if (t<0)
246 t = x;
247 }
248 }
249
250 if (bad) {
251 pk->p_msg |= M_RJ;
252 }
253
254 if (skip) {
255 pk->p_msg |= M_RR;
256 }
257
258 pk->p_rcount = accept;
259 return(accept);
260}
261
262
263pkread(S)
264SDEF;
265{
266register struct pack *pk;
267register x,s;
268int is,cc,xfr,count;
269char *cp, **bp;
270
271 pk = PADDR;
272 xfr = 0;
273 count = 0;
274 while (pkaccept(pk)==0);
275
276
277 while (UCOUNT) {
278
279 x = next[pk->p_pr];
280 is = pk->p_is[x];
281
282 if (is & B_COPY) {
283 cc = MIN(pk->p_isum[x], UCOUNT);
284 if (cc==0 && xfr) {
285 break;
286 }
287 if (is & B_RESID)
288 cp = pk->p_rptr;
289 else {
290 cp = pk->p_ib[x];
291 if (is & B_SHORT) {
292 if (*cp++ & 0200)
293 cp++;
294 }
295 }
296 IOMOVE(cp,cc,B_READ);
297 count += cc;
298 xfr++;
299 pk->p_isum[x] -= cc;
300 if (pk->p_isum[x] == 0) {
301 pk->p_pr = x;
302 bp = (char **)pk->p_ib[x];
303 LOCK;
304 *bp = (char *)pk->p_ipool;
305 pk->p_ipool = bp;
306 pk->p_is[x] = 0;
307 pk->p_rcount--;
308 UNLOCK;
309 pk->p_msg |= M_RR;
310 } else {
311 pk->p_rptr = cp+cc;
312 pk->p_is[x] |= B_RESID;
313 }
314 if (cc==0)
315 break;
316 } else
317 break;
318 }
319 pkoutput(pk);
320 return(count);
321}
322
323
324
325
326pkwrite(S)
327SDEF;
328{
329register struct pack *pk;
330register x;
331int partial;
332caddr_t cp;
333int cc, s, fc, count;
334
335 pk = PADDR;
336 if (pk->p_state&DOWN || !pk->p_state&LIVE) {
337 SETERROR;
338 return(-1);
339 }
340
341 count = UCOUNT;
342 do {
343 LOCK;
344 while (pk->p_xcount>=pk->p_swindow) {
345 pkoutput(pk);
346 PKGETPKT(pk);
347 SLEEP(&pk->p_ps,PKOPRI);
348 }
349 x = next[pk->p_pscopy];
350 while (pk->p_os[x]!=B_NULL) {
351 PKGETPKT(pk);
352 SLEEP(&pk->p_ps,PKOPRI);
353 }
354 pk->p_os[x] = B_MARK;
355 pk->p_pscopy = x;
356 pk->p_xcount++;
357 UNLOCK;
358
359 cp = pk->p_ob[x] = GETEPACK;
360 partial = 0;
361 if ((int)UCOUNT < pk->p_xsize) {
362 cc = UCOUNT;
363 fc = pk->p_xsize - cc;
364 *cp = fc&0177;
365 if (fc > 127) {
366 *cp++ |= 0200;
367 *cp++ = fc>>7;
368 } else
369 cp++;
370 partial = B_SHORT;
371 } else
372 cc = pk->p_xsize;
373 IOMOVE(cp,cc,B_WRITE);
374 pk->p_osum[x] = chksum(pk->p_ob[x], pk->p_xsize);
375 pk->p_os[x] = B_READY+partial;
376 pkoutput(pk);
377 } while (UCOUNT);
378
379 return(count);
380}
381
382pksack(pk)
383register struct pack *pk;
384{
385register x, i;
386
387 i = 0;
388 for(x=pk->p_ps; x!=pk->p_rpr; ) {
389 x = next[x];
390 if (pk->p_os[x]&B_SENT) {
391 i++;
392 pk->p_os[x] = B_NULL;
393 pk->p_state &= ~WAITO;
394 pk->p_xcount--;
395 FREEPACK(pk->p_ob[x], pk->p_bits);
396 pk->p_ps = x;
397 WAKEUP(&pk->p_ps);
398 }
399 }
400 return(i);
401}
402
403
404
405pkoutput(pk)
406register struct pack *pk;
407{
408register x,rx;
409int s;
410char bstate;
411int i;
412SDEF;
413int flag;
414
415 flag = 0;
416 ISYSTEM;
417 LOCK;
418 if (pk->p_obusy++ || OBUSY) {
419 pk->p_obusy--;
420 UNLOCK;
421 return;
422 }
423 UNLOCK;
424
425
426 /*
427 * find seq number and buffer state
428 * of next output packet
429 */
430 if (pk->p_state&RXMIT) {
431 pk->p_nxtps = next[pk->p_rpr];
432 flag++;
433 }
434 x = pk->p_nxtps;
435 bstate = pk->p_os[x];
436
437
438 /*
439 * Send control packet if indicated
440 */
441 if (pk->p_msg) {
442 if (pk->p_msg & ~M_RR || !(bstate&B_READY) ) {
443 x = pk->p_msg;
444 for(i=0; i<8; i++)
445 if (x&1)
446 break; else
447 x >>= 1;
448 x = i;
449 x <<= 3;
450 switch(i) {
451 case CLOSE:
452 break;
453 case RJ:
454 case RR:
455 x += pk->p_pr;
456 break;
457 case SRJ:
458 break;
459 case INITB:
460 x += pksize(pk->p_rsize);
461 break;
462 case INITC:
463 x += pk->p_rwindow;
464 break;
465 case INITA:
466 x += pk->p_rwindow;
467 break;
468 }
469
470 pk->p_msg &= ~mask[i];
471 pkxstart(pk, x, -1);
472 goto out;
473 }
474 }
475
476
477 /*
478 * Don't send data packets if line is marked dead.
479 */
480 if (pk->p_state&DOWN) {
481 WAKEUP(&pk->p_ps);
482 goto out;
483 }
484 /*
485 * Start transmission (or retransmission) of data packets.
486 */
487 if (bstate & (B_READY|B_SENT)) {
488 char seq;
489
490 bstate |= B_SENT;
491 seq = x;
492 pk->p_nxtps = next[x];
493
494 x = 0200+pk->p_pr+(seq<<3);
495 if (bstate & B_SHORT)
496 x |= 0100;
497 pkxstart(pk, x, seq);
498 pk->p_os[seq] = bstate;
499 pk->p_state &= ~RXMIT;
500 pk->p_nout++;
501 goto out;
502 }
503 /*
504 * enable timeout if there's nothing to send
505 * and transmission buffers are languishing
506 */
507 if (pk->p_xcount) {
508 pk->p_timer = 2;
509 pk->p_state |= WAITO;
510 } else
511 pk->p_state &= ~WAITO;
512 WAKEUP(&pk->p_ps);
513out:
514 pk->p_obusy = 0;
515}
516
517
518/*
519 * shut down line by
520 * ignoring new input
521 * letting output drain
522 * releasing space and turning off line discipline
523 */
524pkclose(S)
525SDEF;
526{
527register struct pack *pk;
528register i,s,rbits;
529char **bp;
530int rcheck;
531char *p;
532
533
534 pk = PADDR;
535 pk->p_state |= DRAINO;
536
537
538 /*
539 * try to flush output
540 */
541 i = 0;
542 LOCK;
543 pk->p_timer = 2;
544 while (pk->p_xcount && pk->p_state&LIVE) {
545 if (pk->p_state&(RCLOSE+DOWN) || ++i > 2)
546 break;
547 pkoutput(pk);
548 SLEEP(&pk->p_ps,PKOPRI);
549 }
550 pk->p_timer = 0;
551 pk->p_state |= DOWN;
552 UNLOCK;
553
554
555 /*
556 * try to exchange CLOSE messages
557 */
558 i = 0;
559 while ((pk->p_state&RCLOSE)==0 && i<2) {
560 pk->p_msg = M_CLOSE;
561 pk->p_timer = 2;
562 pkoutput(pk);
563 SLEEP(&pk->p_ps, PKOPRI);
564 i++;
565 }
566
567
568 for(i=0;i<NPLINES;i++)
569 if (pklines[i]==pk) {
570 pklines[i] = NULL;
571 }
572 TURNOFF;
573
574
575 /*
576 * free space
577 */
578 rbits = DTOM(pk->p_rsize);
579 rcheck = 0;
580 for (i=0;i<8;i++) {
581 if (pk->p_os[i]!=B_NULL) {
582 FREEPACK(pk->p_ob[i],pk->p_bits);
583 pk->p_xcount--;
584 }
585 if (pk->p_is[i]!=B_NULL) {
586 FREEPACK(pk->p_ib[i],rbits);
587 rcheck++;
588 }
589 }
590 LOCK;
591 while (pk->p_ipool != NULL) {
592 bp = pk->p_ipool;
593 pk->p_ipool = (char **)*bp;
594 rcheck++;
595 FREEPACK(bp, rbits);
596 }
597 UNLOCK;
598 if (rcheck != pk->p_rwindow) {
599 fprintf(stderr, "r short %d want %d\n",rcheck,pk->p_rwindow);
600 fprintf(stderr, "rcount = %d\n",pk->p_rcount);
601 fprintf(stderr, "xcount = %d\n",pk->p_xcount);
602 }
603 FREEPACK((caddr_t)pk, npbits);
604}
605
606
607
608pkreset(pk)
609register struct pack *pk;
610{
611
612 pk->p_ps = pk->p_pr = pk->p_rpr = 0;
613 pk->p_nxtps = 1;
614}
615
616chksum(s,n)
617register char *s;
618register n;
619{
620 register unsigned sum, t;
621 register x;
622
623 sum = -1;
624 x = 0;
625
626 do {
627 if (sum&0x8000) {
628 sum <<= 1;
629 sum++;
630 } else
631 sum <<= 1;
632 t = sum;
633 sum += (unsigned)*s++ & 0377;
634 x += sum^n;
635 if ((sum&0xffff) <= (t&0xffff)) {
636 sum ^= x;
637 }
638 } while (--n > 0);
639
640 return(sum & 0xffff);
641}
642
643pkline(pk)
644register struct pack *pk;
645{
646register i;
647 for(i=0;i<NPLINES;i++) {
648 if (pklines[i]==pk)
649 return(i);
650 }
651 return(-i);
652}
653
654pkzero(s,n)
655register char *s;
656register n;
657{
658 while (n--)
659 *s++ = 0;
660}
661
662pksize(n)
663register n;
664{
665register k;
666
667 n >>= 5;
668 for(k=0; n >>= 1; k++);
669 return(k);
670}