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 pkfail(), pkzero(), pkoutput(), pkreset(), pkcntl(), pkgetpack();
36 extern int pksack();
37 static void pkdata();
38 static int pkcget();
39 static void xlatestate(struct pack *, int);
40 void xlatecntl(int, int);
41
42 /*
43 * Code added to allow translation of states from numbers to
44 * letters, to be done in such a way as to be meaningful to
45 * John Q. Public
46 */
47 struct {
48 int state;
49 char *msg;
50 } st_trans[] = {
51 DEAD, "Dead!",
52 INITa, "INIT code a",
53 INITb, "INIT code b",
54 LIVE, "O.K.",
55 RXMIT, "Rcv/Xmit",
56 RREJ, "RREJ?",
57 PDEBUG, "PDEBUG?",
58 DRAINO, "Draino...",
59 WAITO, "Waiting",
60 DOWN, "Link down",
61 RCLOSE, "RCLOSE?",
62 BADFRAME, "Bad frame",
63 -1, "End of the line",
64 };
65
66 extern char _Protocol[]; /* Protocol string with (options) */
67
68 #define PKMAXSTMSG 40
69 int Connodata = 0; /* Continuous Non Valid Data Count */
70 int Ntimeout = 0;
71 #define CONNODATA 20 /* Max Continuous Non Valid Data Count */
72 #define NTIMEOUT 50 /* This is not currently used, but maybe future */
73
74 extern jmp_buf Getjbuf;
75
76 /*
77 * start initial synchronization.
78 */
79 struct pack *
pkopen(ifn,ofn)80 pkopen(ifn, ofn)
81 int ifn, ofn;
82 {
83 struct pack *pk;
84 char **bp;
85 int i;
86 int windows = WINDOWS;
87 extern int xpacksize, packsize;
88
89 if ((pk = (struct pack *) calloc(1, sizeof (struct pack))) == NULL)
90 return(NULL);
91 pk->p_ifn = ifn;
92 pk->p_ofn = ofn;
93 DEBUG(7, "Setting up protocol parameters '%s'\n", _Protocol);
94 if ( _Protocol[1] == '(' ) {
95 if (sscanf(_Protocol, "%*c(%d,%d)", &windows, &packsize) == 0)
96 sscanf(_Protocol, "%*c(,%d)", &packsize);
97 windows = ( windows < MINWINDOWS ? WINDOWS :
98 ( windows > MAXWINDOWS ? WINDOWS : windows ) );
99 packsize = ( packsize < MINPACKSIZE ? PACKSIZE :
100 ( packsize > MAXPACKSIZE ? PACKSIZE : packsize ) );
101 }
102 if ( (_Protocol[0] == 'g') && (packsize > OLDPACKSIZE) ) {
103 /*
104 * We reset to OLDPACKSIZE to maintain compatibility
105 * with old limited implementations. Maybe we should
106 * just warn the administrator and continue?
107 */
108 packsize = OLDPACKSIZE;
109 }
110 pk->p_xsize = pk->p_rsize = xpacksize = packsize;
111 pk->p_rwindow = pk->p_swindow = windows;
112
113 /*
114 * allocate input window
115 */
116 for (i = 0; i < pk->p_rwindow; i++) {
117 if ((bp = (char **) malloc((unsigned) pk->p_xsize)) == NULL)
118 break;
119 *bp = (char *) pk->p_ipool;
120 pk->p_ipool = bp;
121 }
122 if (i == 0)
123 return(NULL);
124 pk->p_rwindow = i;
125
126 /*
127 * start synchronization
128 */
129 pk->p_msg = pk->p_rmsg = M_INITA;
130 pkoutput(pk);
131
132 for (i = 0; i < PKMAXSTMSG; i++) {
133 pkgetpack(pk);
134 if ((pk->p_state & LIVE) != 0)
135 break;
136 }
137 if (i >= PKMAXSTMSG)
138 return(NULL);
139
140 pkreset(pk);
141 return(pk);
142 }
143
144 /*
145 * input framing and block checking.
146 * frame layout for most devices is:
147 *
148 * S|K|X|Y|C|Z| ... data ... |
149 *
150 * where S == initial synch byte
151 * K == encoded frame size (indexes pksizes[])
152 * X, Y == block check bytes
153 * C == control byte
154 * Z == XOR of header (K^X^Y^C)
155 * data == 0 or more data bytes
156 *
157 */
158 #define GETRIES 10
159
160 /*
161 * Byte collection.
162 */
163 void
pkgetpack(ipk)164 pkgetpack(ipk)
165 struct pack *ipk;
166 {
167 char *p;
168 struct pack *pk;
169 struct header *h;
170 unsigned short sum;
171 int k, tries, ifn, noise;
172 char **bp, hdchk;
173
174 pk = ipk;
175 /*
176 * If we are known to be DOWN, or if we've received too many garbage
177 * packets or timeouts, give up without a fight.
178 */
179 if ((pk->p_state & DOWN) || Connodata > CONNODATA || Ntimeout > NTIMEOUT)
180 pkfail();
181 ifn = pk->p_ifn;
182 h = &pk->p_ihbuf;
183
184 /*
185 * Attempt no more than GETRIES times to read a packet. The only valid
186 * exit from this loop is a return. Break forces a failure.
187 */
188 for (tries = 0; tries < GETRIES; tries++) {
189 /*
190 * Read header.
191 * First look for SYN. If more than 3 * packetsize characters
192 * go by w/o a SYN, request a retransmit.
193 */
194 p = (caddr_t) h;
195 noise = 0;
196 for ( ; ; ) {
197 if (pkcget(ifn, p, HDRSIZ) != SUCCESS) {
198 DEBUG(7,
199 "Alarm while looking for SYN -- request RXMIT\n%s", "");
200 goto retransmit;
201 }
202 if (*p == SYN)
203 break; /* got it */
204 else {
205 char *pp, *pend;
206
207 DEBUG(7, "first char not SYN (%x)\n", *p&0xff);
208 if ((pp = memchr(p, SYN, HDRSIZ)) != NULL) {
209 pend = p + HDRSIZ;
210 while (pp < pend)
211 *p++ = *pp++;
212 /* Now look for remainder of header */
213 if (pkcget(ifn, p, pend - p) !=
214 SUCCESS) {
215 DEBUG(7,
216 "Alarm while looking for header -- request RXMIT\n%s", "");
217 goto retransmit;
218 }
219 p = (caddr_t) h;
220 break; /* got entire header */
221 }
222 }
223 if ((noise += HDRSIZ) > 3 * pk->p_rsize) {
224 DEBUG(7,
225 "No SYN in %d characters -- request RXMIT\n", noise);
226 goto retransmit;
227 }
228 }
229 /* Validate the header */
230 Connodata++;
231 hdchk = p[1] ^ p[2] ^ p[3] ^ p[4];
232 sum = ((unsigned) p[2] & 0377) | ((unsigned) p[3] << 8);
233 h->sum = sum;
234 k = h->ksize;
235 if (hdchk != h->ccntl) {
236 /* bad header */
237 DEBUG(7, "bad header checksum\n%s", "");
238 return;
239 }
240
241 if (k == 9) { /* control packet */
242 if (((h->sum + h->cntl) & 0xffff) == CHECK) {
243 pkcntl(h->cntl, pk);
244 xlatestate(pk, 7);
245 } else {
246 /* bad header */
247 DEBUG(7, "bad header (k == 9) 0%o\n", h->cntl&0xff);
248 pk->p_state |= BADFRAME;
249 }
250 return;
251 }
252 /* data packet */
253 if (k && pksizes[k] != pk->p_rsize)
254 return;
255 pk->p_rpr = h->cntl & MOD8;
256 pksack(pk);
257 if ((bp = pk->p_ipool) == NULL) {
258 DEBUG(7, "bp NULL\n%s", "");
259 return;
260 }
261 pk->p_ipool = (char **) *bp;
262 /* Header checks out, go for data */
263 if (pkcget(pk->p_ifn, (char *) bp, pk->p_rsize) == SUCCESS) {
264 pkdata(h->cntl, h->sum, pk, bp);
265 Ntimeout = 0;
266 return;
267 }
268 DEBUG(7, "Alarm while reading data -- request RXMIT\n%s", "");
269 retransmit:
270 /*
271 * Transmission error or excessive noise. Send a RXMIT
272 * and try again.
273 */
274 /*
275 Retries++;
276 */
277 pk->p_msg |= pk->p_rmsg;
278 if (pk->p_msg == 0)
279 pk->p_msg |= M_RR;
280 if ((pk->p_state & LIVE) == LIVE)
281 pk->p_state |= RXMIT;
282 pkoutput(pk);
283 }
284 DEBUG(7, "pkgetpack failed after %d tries\n", tries);
285 pkfail();
286 }
287
288 /*
289 * Translate pk->p_state into something printable.
290 */
291 static void
xlatestate(pk,dbglvl)292 xlatestate(pk, dbglvl)
293 struct pack *pk;
294 int dbglvl;
295 {
296 int i;
297 char delimc = ' ', msgline[80], *buf = msgline;
298
299 if (Debug < dbglvl)
300 return;
301 sprintf(buf, "state -");
302 buf += strlen(buf);
303 for(i = 0; st_trans[i].state != -1; i++) {
304 if (pk->p_state&st_trans[i].state){
305 sprintf(buf, "%c[%s]", delimc, st_trans[i].msg);
306 buf += strlen(buf);
307 delimc = '&';
308 }
309 }
310 sprintf(buf, " (0%o)\n", pk->p_state);
311 DEBUG(dbglvl, "%s", msgline);
312 return;
313 }
314
315 static void
pkdata(c,sum,pk,bp)316 pkdata(c, sum, pk, bp)
317 struct pack *pk;
318 unsigned short sum;
319 char c;
320 char **bp;
321 {
322 int x;
323 int t;
324 char m;
325
326 if (pk->p_state & DRAINO || !(pk->p_state & LIVE)) {
327 pk->p_msg |= pk->p_rmsg;
328 pkoutput(pk);
329 goto drop;
330 }
331 t = next[pk->p_pr];
332 for(x=pk->p_pr; x!=t; x = (x-1)&7) {
333 if (pk->p_is[x] == 0)
334 goto slot;
335 }
336 drop:
337 *bp = (char *)pk->p_ipool;
338 pk->p_ipool = bp;
339 return;
340
341 slot:
342 m = mask[x];
343 pk->p_imap |= m;
344 pk->p_is[x] = c;
345 pk->p_isum[x] = sum;
346 pk->p_ib[x] = (char *)bp;
347 }
348
349 /*
350 * Start transmission on output device associated with pk.
351 * For asynch devices (t_line==1) framing is
352 * imposed. For devices with framing and crc
353 * in the driver (t_line==2) the transfer is
354 * passed on to the driver.
355 */
356 void
pkxstart(pk,cntl,x)357 pkxstart(pk, cntl, x)
358 struct pack *pk;
359 int x;
360 char cntl;
361 {
362 char *p;
363 short checkword;
364 char hdchk;
365
366 p = (caddr_t) &pk->p_ohbuf;
367 *p++ = SYN;
368 if (x < 0) {
369 *p++ = hdchk = 9;
370 checkword = cntl;
371 } else {
372 *p++ = hdchk = pk->p_lpsize;
373 checkword = pk->p_osum[x] ^ (unsigned)(cntl & 0377);
374 }
375 checkword = CHECK - checkword;
376 *p = checkword;
377 hdchk ^= *p++;
378 *p = checkword>>8;
379 hdchk ^= *p++;
380 *p = cntl;
381 hdchk ^= *p++;
382 *p = hdchk;
383
384 /*
385 * writes
386 */
387 if (Debug >= 9)
388 xlatecntl(1, cntl);
389
390 p = (caddr_t) & pk->p_ohbuf;
391 if (x < 0) {
392 if ((*Write)(pk->p_ofn, p, HDRSIZ) != HDRSIZ) {
393 DEBUG(4, "pkxstart, write failed, %s\n",
394 strerror(errno));
395 logent(strerror(errno), "PKXSTART WRITE");
396 pkfail();
397 /* NOT REACHED */
398 }
399 } else {
400 char buf[MAXPACKSIZE + HDRSIZ];
401
402 memcpy(buf, p, HDRSIZ);
403 memcpy(buf+HDRSIZ, pk->p_ob[x], pk->p_xsize);
404 if ((*Write)(pk->p_ofn, buf, pk->p_xsize + HDRSIZ) !=
405 pk->p_xsize + HDRSIZ) {
406 DEBUG(4, "pkxstart, write failed, %s\n",
407 strerror(errno));
408 logent(strerror(errno), "PKXSTART WRITE");
409 pkfail();
410 /* NOT REACHED */
411 }
412 Connodata = 0;
413 }
414 if (pk->p_msg)
415 pkoutput(pk);
416 }
417
418 /*
419 * get n characters from input
420 * b -> buffer for characters
421 * fn -> file descriptor
422 * n -> requested number of characters
423 * return:
424 * SUCCESS -> n chars successfully read
425 * FAIL -> o.w.
426 */
427
428 static int
pkcget(fn,b,n)429 pkcget(fn, b, n)
430 int n;
431 char *b;
432 int fn;
433 {
434 int ret;
435 #ifdef PKSPEEDUP
436 extern int linebaudrate;
437 int donap = (linebaudrate > 0 && linebaudrate < 4800);
438 #endif /* PKSPEEDUP */
439
440 if (n == 0)
441 return(SUCCESS);
442 if (setjmp(Getjbuf)) {
443 Ntimeout++;
444 DEBUG(4, "pkcget: alarm %d\n", Ntimeout);
445 return(FAIL);
446 }
447
448 (void) alarm( (unsigned) ( 10 + (n >> 7)) );
449
450 for (;;) {
451 ret = (*Read)(fn, b, n);
452 (void) alarm(0);
453 if (ret == 0) {
454 DEBUG(4, "pkcget, read failed, EOF\n", 0);
455 /*
456 * Device has decided that the connection has no
457 * more data to send. Any further tries are futile...
458 * (The only other way to get a zero return value
459 * is to read a zero length message from a STREAM.
460 * However, uucp *never* sends zero length messages
461 * over any sort of channel...)
462 */
463 pkfail();
464 /* NOT REACHED */
465 }
466 if (ret < 0) {
467 DEBUG(4, "pkcget, read failed, %s\n",
468 strerror(errno));
469 logent(strerror(errno), "PKCGET READ");
470 pkfail();
471 /* NOT REACHED */
472 }
473 if ((n -= ret) <= 0)
474 break;
475 #ifdef PKSPEEDUP
476 if (donap) {
477 #if defined(BSD4_2) || defined(ATTSVR4)
478 /* wait for more chars to come in */
479 nap((n * HZ * 10) / linebaudrate); /* n char times */
480 #else
481 sleep(1);
482 #endif
483 }
484 #endif /* PKSPEEDUP */
485 b += ret;
486 (void) alarm( (unsigned) ( 10 + (n >> 7)) );
487 }
488 (void) alarm(0);
489 return(SUCCESS);
490 }
491
492 /*
493 * role == 0: receive
494 * role == 1: send
495 */
496 void
xlatecntl(role,cntl)497 xlatecntl(role, cntl)
498 int role;
499 int cntl;
500 {
501 static char *cntltype[4] = {"CNTL, ", "ALT, ", "DATA, ", "SHORT, "};
502 static char *cntlxxx[8] = {"ZERO, ", "CLOSE, ", "RJ, ", "SRJ, ",
503 "RR, ", "INITC, ", "INITB, ", "INITA, "};
504 char dbgbuf[128];
505 char *ptr;
506
507 ptr = dbgbuf;
508 strcpy(ptr, role ? "send " : "recv ");
509 ptr += strlen(ptr);
510
511 strcpy(ptr, cntltype[(cntl&0300)>>6]);
512 ptr += strlen(ptr);
513
514 if (cntl&0300) {
515 /* data packet */
516 if (role)
517 sprintf(ptr, "loc %o, rem %o\n", (cntl & 070) >> 3, cntl & 7);
518 else
519 sprintf(ptr, "loc %o, rem %o\n", cntl & 7, (cntl & 070) >> 3);
520 } else {
521 /* control packet */
522 strcpy(ptr, cntlxxx[(cntl&070)>>3]);
523 ptr += strlen(ptr);
524 sprintf(ptr, "val %o\n", cntl & 7);
525 }
526
527 DEBUG(1, dbgbuf, 0);
528 }
529