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