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