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