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