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 *
pkopen(ifn,ofn)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
pkgetpack(pk)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
pkdata(c,sum,pk,bp)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 */
pkxstart(pk,cntl,x)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
cgalarm()350 cgalarm()
351 {
352 longjmp(Getjbuf, 1);
353 }
354
pkcget(fn,b,n)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