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