xref: /original-bsd/usr.bin/uucp/uucico/pk0.c (revision 817cfbae)
1 /*-
2  * Copyright (c) 1985 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.proprietary.c%
6  */
7 
8 #ifndef lint
9 static char sccsid[] = "@(#)pk0.c	5.10 (Berkeley) 04/24/91";
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  */
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 
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*/
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*/
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 
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 
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*/
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 
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
555 bzero(s,n)
556 register char *s;
557 register n;
558 {
559 	while (n--)
560 		*s++ = 0;
561 }
562 #endif !BSD4_2
563 
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