xref: /original-bsd/usr.bin/uucp/uucico/pk1.c (revision 9c4519f8)
1 #ifndef lint
2 static char sccsid[] = "@(#)pk1.c	5.2 (Berkeley) 01/22/85";
3 #endif
4 
5 #ifdef USG
6 #include <sys/types.h>
7 #endif USG
8 #include <sys/param.h>
9 #include "pk.h"
10 #include "uucp.h"
11 #include <sys/buf.h>
12 #include <setjmp.h>
13 #include <signal.h>
14 #ifdef BSD4_2
15 #include <sys/time.h>
16 #endif BSD4_2
17 
18 #ifdef VMS
19 #include <eunice/eunice.h>
20 #include <vms/iodef.h>
21 #include <vms/ssdef.h>
22 int iomask[2];
23 #endif VMS
24 
25 #define PKMAXSTMSG 40
26 #define	PKTIME	25
27 #define CONNODATA 10
28 #define NTIMEOUT 10
29 
30 extern int Errorrate;
31 extern int errno;
32 extern char *sys_errlist[];
33 extern jmp_buf Sjbuf;
34 extern	char *malloc();
35 
36 int Connodata = 0;
37 int Ntimeout = 0;
38 /*
39  * packet driver support routines
40  *
41  */
42 
43 struct pack *pklines[NPLINES];
44 
45 /*
46  * start initial synchronization.
47  */
48 
49 struct pack *
50 pkopen(ifn, ofn)
51 int ifn, ofn;
52 {
53 	register struct pack *pk;
54 	register char **bp;
55 	register int i;
56 
57 	if (++pkactive >= NPLINES)
58 		return NULL;
59 	if ((pk = (struct pack *) malloc(sizeof (struct pack))) == NULL)
60 		return NULL;
61 	bzero((caddr_t) pk, sizeof (struct pack));
62 	pk->p_ifn = ifn;
63 	pk->p_ofn = ofn;
64 	pk->p_xsize = pk->p_rsize = PACKSIZE;
65 	pk->p_rwindow = pk->p_swindow = WINDOWS;
66 	/*  allocate input windows */
67 	for (i = 0; i < pk->p_rwindow; i++) {
68 		if ((bp = (char **) malloc((unsigned)pk->p_xsize)) == NULL)
69 			break;
70 		*bp = (char *) pk->p_ipool;
71 		pk->p_ipool = bp;
72 	}
73 	if (i == 0)
74 		return NULL;
75 	pk->p_rwindow = i;
76 
77 	/* start synchronization */
78 	pk->p_msg = pk->p_rmsg = M_INITA;
79 	for (i = 0; i < NPLINES; i++) {
80 		if (pklines[i] == NULL) {
81 			pklines[i] = pk;
82 			break;
83 		}
84 	}
85 	if (i >= NPLINES)
86 		return NULL;
87 	pkoutput(pk);
88 
89 	for (i = 0; i < PKMAXSTMSG; i++) {
90 		pkgetpack(pk);
91 		if ((pk->p_state & LIVE) != 0)
92 			break;
93 	}
94 	if (i >= PKMAXSTMSG)
95 		return NULL;
96 
97 	pkreset(pk);
98 	return pk;
99 }
100 
101 
102 /*
103  * input framing and block checking.
104  * frame layout for most devices is:
105  *
106  *	S|K|X|Y|C|Z|  ... data ... |
107  *
108  *	where 	S	== initial synch byte
109  *		K	== encoded frame size (indexes pksizes[])
110  *		X, Y	== block check bytes
111  *		C	== control byte
112  *		Z	== XOR of header (K^X^Y^C)
113  *		data	== 0 or more data bytes
114  *
115  */
116 
117 int pksizes[] = {
118 	1, 32, 64, 128, 256, 512, 1024, 2048, 4096, 1
119 };
120 
121 #define GETRIES 5
122 /*
123  * Pseudo-dma byte collection.
124  */
125 
126 pkgetpack(ipk)
127 struct pack *ipk;
128 {
129 	int k, tries, noise;
130 	register char *p;
131 	register struct pack *pk;
132 	register struct header *h;
133 	unsigned short sum;
134 	int ifn;
135 	char **bp;
136 	char hdchk;
137 
138 	pk = ipk;
139 	if ((pk->p_state & DOWN) || Connodata > CONNODATA || Ntimeout > NTIMEOUT)
140 		pkfail();
141 	ifn = pk->p_ifn;
142 
143 	/* find HEADER */
144 	for (tries = 0, noise = 0; tries < GETRIES; ) {
145 		p = (caddr_t) &pk->p_ihbuf;
146 		if (pkcget(ifn, p, 1) == SUCCESS) {
147 			if (*p++ == SYN) {
148 				if (pkcget(ifn, p, HDRSIZ-1) == SUCCESS)
149 					break;
150 			} else
151 				if (noise++ < (3*pk->p_rsize))
152 					continue;
153 			DEBUG(4, "Noisy line - set up RXMIT", "");
154 			noise = 0;
155 		}
156 		/* set up retransmit or REJ */
157 		tries++;
158 		pk->p_msg |= pk->p_rmsg;
159 		if (pk->p_msg == 0)
160 			pk->p_msg |= M_RR;
161 		if ((pk->p_state & LIVE) == LIVE)
162 			pk->p_state |= RXMIT;
163 		pkoutput(pk);
164 
165 		if (*p != SYN)
166 			continue;
167 		p++;
168 		if (pkcget(ifn, p, HDRSIZ - 1) == SUCCESS)
169 			break;
170 	}
171 	if (tries >= GETRIES) {
172 		DEBUG(4, "tries = %d\n", tries);
173 		pkfail();
174 	}
175 
176 	Connodata++;
177 	h = (struct header * ) &pk->p_ihbuf;
178 	p = (caddr_t) h;
179 	hdchk = p[1] ^ p[2] ^ p[3] ^ p[4];
180 	p += 2;
181 	sum = (unsigned) *p++ & 0377;
182 	sum |= (unsigned) *p << 8;
183 	h->sum = sum;
184 	DEBUG(7, "rec h->cntl 0%o\n", h->cntl&0xff);
185 	k = h->ksize;
186 	if (hdchk != h->ccntl) {
187 		/* bad header */
188 		DEBUG(7, "bad header 0%o,", hdchk&0xff);
189 		DEBUG(7, "h->ccntl 0%o\n", h->ccntl&0xff);
190 		return;
191 	}
192 	if (k == 9) {
193 		if (((h->sum + h->cntl) & 0xffff) == CHECK) {
194 			pkcntl(h->cntl, pk);
195 			DEBUG(7, "state - 0%o\n", pk->p_state);
196 		} else {
197 			/*  bad header */
198 			pk->p_state |= BADFRAME;
199 			DEBUG(7, "bad header (k==9) 0%o\n", h->cntl&0xff);
200 		}
201 		return;
202 	}
203 	if (k && pksizes[k] == pk->p_rsize) {
204 		pk->p_rpr = h->cntl & MOD8;
205 		pksack(pk);
206 		Connodata = 0;
207 		bp = pk->p_ipool;
208 		if (bp == NULL) {
209 			DEBUG(7, "bp NULL %s\n", "");
210 			return;
211 		}
212 		pk->p_ipool = (char **) *bp;
213 	} else {
214 		return;
215 	}
216 	if (pkcget(pk->p_ifn, (char *) bp, pk->p_rsize) == SUCCESS)
217 		pkdata(h->cntl, h->sum, pk, (char **) bp);
218 	Ntimeout = 0;
219 }
220 
221 pkdata(c, sum, pk, bp)
222 char c;
223 unsigned short sum;
224 register struct pack *pk;
225 char **bp;
226 {
227 	register x;
228 	int t;
229 	char m;
230 
231 	if (pk->p_state & DRAINO || !(pk->p_state & LIVE)) {
232 		pk->p_msg |= pk->p_rmsg;
233 		pkoutput(pk);
234 		goto drop;
235 	}
236 	t = next[pk->p_pr];
237 	for(x=pk->p_pr; x!=t; x = (x-1)&7) {
238 		if (pk->p_is[x] == 0)
239 			goto slot;
240 	}
241 drop:
242 	*bp = (char *)pk->p_ipool;
243 	pk->p_ipool = bp;
244 	return;
245 
246 slot:
247 	m = mask[x];
248 	pk->p_imap |= m;
249 	pk->p_is[x] = c;
250 	pk->p_isum[x] = sum;
251 	pk->p_ib[x] = (char *)bp;
252 }
253 
254 
255 
256 /*
257  * setup input transfers
258  */
259 #define PKMAXBUF 128
260 /*
261  * Start transmission on output device associated with pk.
262  * For asynch devices (t_line==1) framing is
263  * imposed.  For devices with framing and crc
264  * in the driver (t_line==2) the transfer is
265  * passed on to the driver.
266  */
267 pkxstart(pk, cntl, x)
268 register struct pack *pk;
269 char cntl;
270 register x;
271 {
272 	register char *p;
273 	short checkword;
274 	char hdchk;
275 
276 	p = (caddr_t) &pk->p_ohbuf;
277 	*p++ = SYN;
278 	if (x < 0) {
279 		*p++ = hdchk = 9;
280 		checkword = cntl;
281 	}
282 	else {
283 		*p++ = hdchk = pk->p_lpsize;
284 		checkword = pk->p_osum[x] ^ (unsigned)(cntl & 0377);
285 	}
286 	checkword = CHECK - checkword;
287 	*p = checkword;
288 	hdchk ^= *p++;
289 	*p = checkword>>8;
290 	hdchk ^= *p++;
291 	*p = cntl;
292 	hdchk ^= *p++;
293 	*p = hdchk;
294 	/*  writes  */
295 	DEBUG(7, "send 0%o\n", cntl&0xff);
296 	p = (caddr_t) & pk->p_ohbuf;
297 	if (x < 0) {
298 		if(write(pk->p_ofn, p, HDRSIZ) != HDRSIZ) {
299 			alarm(0);
300 			logent("PKXSTART write failed", sys_errlist[errno]);
301 			longjmp(Sjbuf, 4);
302 		}
303 	}
304 	else {
305 		char buf[PKMAXBUF + HDRSIZ], *b;
306 		int i;
307 		for (i = 0, b = buf; i < HDRSIZ; i++)
308 			*b++ = *p++;
309 		for (i = 0, p = pk->p_ob[x]; i < pk->p_xsize; i++)
310 			*b++ = *p++;
311 		if (write(pk->p_ofn, buf, pk->p_xsize + HDRSIZ) != (HDRSIZ + pk->p_xsize)) {
312 			alarm(0);
313 			logent("PKXSTART write failed", sys_errlist[errno]);
314 			longjmp(Sjbuf, 5);
315 		}
316 		Connodata = 0;
317 	}
318 	if (pk->p_msg)
319 		pkoutput(pk);
320 }
321 
322 
323 pkmove(p1, p2, count, flag)
324 char *p1, *p2;
325 int count, flag;
326 {
327 	register char *s, *d;
328 	register int i;
329 
330 	if (flag == B_WRITE) {
331 		s = p2;
332 		d = p1;
333 	}
334 	else {
335 		s = p1;
336 		d = p2;
337 	}
338 	for (i = 0; i < count; i++)
339 		*d++ = *s++;
340 }
341 
342 
343 /***
344  *	pkcget(fn, b, n)	get n characters from input
345  *	char *b;		- buffer for characters
346  *	int fn;			- file descriptor
347  *	int n;			- requested number of characters
348  *
349  *	return codes:
350  *		n - number of characters returned
351  *		0 - end of file
352  */
353 
354 jmp_buf Getjbuf;
355 cgalarm()
356 {
357 	longjmp(Getjbuf, 1);
358 }
359 
360 pkcget(fn, b, n)
361 int fn, n;
362 register char *b;
363 {
364 	register int nchars, ret;
365 	extern int linebaudrate;
366 #ifdef BSD4_2
367 	long r, itime = 0;
368 	struct timeval tv;
369 #endif BSD4_2
370 #ifdef VMS
371 	short iosb[4];
372 	int SYS$QioW();	/* use this for long reads on vms */
373 #endif VMS
374 
375 	if (setjmp(Getjbuf)) {
376 		Ntimeout++;
377 		DEBUG(4, "pkcget: alarm %d\n", Ntimeout);
378 		return FAIL;
379 	}
380 	signal(SIGALRM, cgalarm);
381 
382 	alarm(PKTIME);
383 	for (nchars = 0; nchars < n; ) {
384 #ifndef VMS
385 		ret = read(fn, b, n - nchars);
386 #else VMS
387 		_$Cancel_IO_On_Signal = FD_FAB_Pointer[fn];
388 		ret = SYS$QioW(_$EFN,(FD_FAB_Pointer[fn]->fab).fab$l_stv,
389 				IO$_READVBLK|IO$M_NOFILTR|IO$M_NOECHO,
390 				iosb,0,0,b,n-nchars,0,
391 				iomask,0,0);
392 		_$Cancel_IO_On_Signal = 0;
393 		if (ret == SS$_NORMAL)
394 			ret = iosb[1]+iosb[3];   /* get length of transfer */
395 		else
396 			ret = 0;
397 #endif VMS
398 		if (ret == 0) {
399 			alarm(0);
400 			return FAIL;
401 		}
402 		if (ret <= 0) {
403 			alarm(0);
404 			logent("PKCGET read failed", sys_errlist[errno]);
405 			longjmp(Sjbuf, 6);
406 		}
407  		b += ret;
408 		nchars += ret;
409 		if (nchars < n)
410 #ifndef BSD4_2
411 			if (linebaudrate > 0 && linebaudrate < 4800)
412 				sleep(1);
413 #else BSD4_2
414 			if (linebaudrate > 0) {
415 				r = (n - nchars) * 100000;
416 				r = r / linebaudrate;
417 				r = (r * 100) - itime;
418 				itime = 0;
419 				/* we predict that more than 1/50th of a
420 				   second will go by before the read will
421 				   give back all that we want. */
422 			 	if (r > 20000) {
423 					tv.tv_sec = r / 1000000L;
424 					tv.tv_usec = r % 1000000L;
425 					DEBUG(11, "PKCGET stall for %d", tv.tv_sec);
426 					DEBUG(11, ".%06d sec\n", tv.tv_usec);
427 					(void) select (fn, (int *)0, (int *)0, (int *)0, &tv);
428 			    	}
429 		    	}
430 #endif BSD4_2
431 	}
432 	alarm(0);
433 	return SUCCESS;
434 }
435