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