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