|
|
1.1 root 1: #ifndef lint
2: static char sccsid[] = "@(#)condevs.c 5.21 (Berkeley) 5/11/89";
3: #endif
4:
5: extern int errno;
6: extern char *sys_errlist[];
7:
8: /*
9: * Here are various dialers to establish the machine-machine connection.
10: * conn.c/condevs.c was glued together by Mike Mitchell.
11: * The dialers were supplied by many people, to whom we are grateful.
12: *
13: * ---------------------------------------------------------------------
14: * NOTE:
15: * There is a bug that occurs at least on PDP11s due to a limitation of
16: * setjmp/longjmp. If the routine that does a setjmp is interrupted
17: * and longjmp-ed to, it loses its register variables (on a pdp11).
18: * What works is if the routine that does the setjmp
19: * calls a routine and it is the *subroutine* that is interrupted.
20: *
21: * Anyway, in conclusion, condevs.c is plagued with register variables
22: * that are used inside
23: * if (setjmp(...)) {
24: * ....
25: * }
26: *
27: * THE FIX: Don't declare variables to be register
28: */
29:
30: #include "condevs.h"
31: #include "pathnames.h"
32:
33: struct condev condevs[] = {
34: { "DIR", "direct", diropn, nulldev, dircls },
35: #ifdef DATAKIT
36: { "DK", "datakit", dkopn, nulldev, nulldev },
37: #endif DATAKIT
38: #ifdef PNET
39: { "PNET", "pnet", pnetopn, nulldev, nulldev },
40: #endif PNET
41: #ifdef UNETTCP
42: { "TCP", "TCP", unetopn, nulldev, unetcls },
43: #endif UNETTCP
44: #ifdef BSDTCP
45: { "TCP", "TCP", bsdtcpopn, nulldev, bsdtcpcls },
46: #endif BSDTCP
47: #ifdef MICOM
48: { "MICOM", "micom", micopn, nulldev, miccls },
49: #endif MICOM
50: #ifdef DN11
51: { "ACU", "dn11", Acuopn, dnopn, dncls },
52: #endif DN11
53: #ifdef HAYES
54: { "ACU", "hayes", Acuopn, hyspopn, hyscls },
55: { "ACU", "hayespulse", Acuopn, hyspopn, hyscls },
56: { "ACU", "hayestone", Acuopn, hystopn, hyscls },
57: { "WATS", "hayestone", Acuopn, hystopn, hyscls },
58: #endif HAYES
59: #ifdef HAYES2400
60: { "ACU", "hayes2400", Acuopn, hyspopn24, hyscls24 },
61: { "ACU", "hayes2400pulse", Acuopn, hyspopn24, hyscls24 },
62: { "ACU", "hayes2400tone", Acuopn, hystopn24, hyscls24 },
63: #endif HAYES2400
64: #ifdef HAYESQ /* a version of hayes that doesn't use result codes */
65: { "ACU", "hayesq", Acuopn, hysqpopn, hysqcls },
66: { "ACU", "hayesqpulse", Acuopn, hysqpopn, hysqcls },
67: { "ACU", "hayesqtone", Acuopn, hysqtopn, hysqcls },
68: #endif HAYESQ
69: #ifdef CDS224
70: { "ACU", "cds224", Acuopn, cdsopn224, cdscls224},
71: #endif CDS224
72: #ifdef NOVATION
73: { "ACU", "novation", Acuopn, novopn, novcls},
74: #endif NOVATION
75: #ifdef DF02
76: { "ACU", "DF02", Acuopn, df2opn, df2cls },
77: #endif DF02
78: #ifdef DF112
79: { "ACU", "DF112P", Acuopn, df12popn, df12cls },
80: { "ACU", "DF112T", Acuopn, df12topn, df12cls },
81: #endif DF112
82: #ifdef VENTEL
83: { "ACU", "ventel", Acuopn, ventopn, ventcls },
84: #endif VENTEL
85: #ifdef PENRIL
86: { "ACU", "penril", Acuopn, penopn, pencls },
87: #endif PENRIL
88: #ifdef VADIC
89: { "ACU", "vadic", Acuopn, vadopn, vadcls },
90: #endif VADIC
91: #ifdef VA212
92: { "ACU", "va212", Acuopn, va212opn, va212cls },
93: #endif VA212
94: #ifdef VA811S
95: { "ACU", "va811s", Acuopn, va811opn, va811cls },
96: #endif VA811S
97: #ifdef VA820
98: { "ACU", "va820", Acuopn, va820opn, va820cls },
99: { "WATS", "va820", Acuopn, va820opn, va820cls },
100: #endif VA820
101: #ifdef RVMACS
102: { "ACU", "rvmacs", Acuopn, rvmacsopn, rvmacscls },
103: #endif RVMACS
104: #ifdef VMACS
105: { "ACU", "vmacs", Acuopn, vmacsopn, vmacscls },
106: #endif VMACS
107: #ifdef SYTEK
108: { "SYTEK", "sytek", sykopn, nulldev, sykcls },
109: #endif SYTEK
110: #ifdef ATT2224
111: { "ACU", "att", Acuopn, attopn, attcls },
112: #endif ATT2224
113:
114:
115: /* Insert new entries before this line */
116: { NULL, NULL, NULL, NULL, NULL }
117: };
118:
119: /*
120: * nulldev a null device (returns CF_DIAL)
121: */
122: nulldev()
123: {
124: return CF_DIAL;
125: }
126:
127: /*
128: * nodev a null device (returns CF_NODEV)
129: */
130: nodev()
131: {
132: return CF_NODEV;
133: }
134:
135: /*
136: * Generic devices look through L-devices and call the CU_open routines for
137: * appropriate devices. Some things, like the tcp/ip interface, or direct
138: * connect, do not use the CU_open entry. ACUs must search to find the
139: * right routine to call.
140: */
141:
142: /*
143: * diropn(flds) connect to hardware line
144: *
145: * return codes:
146: * > 0 - file number - ok
147: * FAIL - failed
148: */
149: diropn(flds)
150: register char *flds[];
151: {
152: register int dcr, status;
153: struct Devices dev;
154: char dcname[20];
155: FILE *dfp;
156: #ifdef VMSDTR /* Modem control on vms(works dtr) */
157: int modem_control;
158: short iosb[4];
159: int sys$qiow(); /* use this for long reads on vms */
160: int ret;
161: long mode[2];
162: modem_control = 0;
163: #endif
164: dfp = fopen(DEVFILE, "r");
165: if (dfp == NULL) {
166: syslog(LOG_ERR, "fopen(%s) failed: %m", DEVFILE);
167: cleanup(FAIL);
168: }
169: while ((status = rddev(dfp, &dev)) != FAIL) {
170: #ifdef VMSDTR /* Modem control on vms(works dtr) */
171: /* If we find MOD in the device type field we go into action */
172: if (strcmp(dev.D_type, "MOD") == SAME) {
173: modem_control = 1;
174: DEBUG(7, "Setting Modem control to %d",modem_control);
175: }
176: if (strcmp(flds[F_CLASS], dev.D_class) != SAME)
177: continue;
178: /*
179: * Modem control on vms(works dtr) Take anything in MOD class.
180: * It probably should work differently anyway so we can have
181: * multiple hardwired lines.
182: */
183: if (!modem_control&&strcmp(flds[F_PHONE], dev.D_line) != SAME)
184: #else !VMSDTR
185: if (strcmp(flds[F_CLASS], dev.D_class) != SAME)
186: continue;
187: if (strcmp(flds[F_PHONE], dev.D_line) != SAME)
188: #endif !VMSDTR
189: continue;
190: if (mlock(dev.D_line) != FAIL)
191: break;
192: }
193: fclose(dfp);
194: if (status == FAIL) {
195: logent("DEVICE", "NO");
196: return CF_NODEV;
197: }
198:
199: sprintf(dcname, "%s/%s", _PATH_DEV, dev.D_line);
200: if (setjmp(Sjbuf)) {
201: DEBUG(4, "Open timed out\n", CNULL);
202: delock(dev.D_line);
203: return CF_DIAL;
204: }
205: signal(SIGALRM, alarmtr);
206: /* For PC Pursuit, it could take a while to call back */
207: alarm( strcmp(flds[F_LINE], "PCP") ? 10 : MAXMSGTIME*4 );
208: getnextfd();
209: errno = 0;
210: DEBUG(4,"Opening %s\n",dcname);
211: dcr = open(dcname, 2); /* read/write */
212: #ifdef VMSDTR /* Modem control on vms(works dtr) */
213: fflush(stdout);
214: if (modem_control) { /* Did we have MOD in the device type field ? */
215: /* Sense the current terminal setup and save it */
216: if ((ret = sys$qiow(_$EFN,(fd_fab_pointer[dcr]->fab).fab$l_stv,
217: IO$_SENSEMODE,iosb,0,0,mode,8,0,0,0,0))
218: != SS$_NORMAL) {
219: DEBUG(7, "ret status on sense failed on Modem sense=%x<", ret);
220: return CF_DIAL;
221: }
222: mode[1] |= TT$M_MODEM; /* Or in modem control(DTR) */
223: /* Now set the new terminal characteristics */
224: /* This is temporary and will go away when we let go of it */
225: if ((ret = sys$qiow(_$EFN,(fd_fab_pointer[dcr]->fab).fab$l_stv,
226: IO$_SETMODE,iosb,0,0,mode,8,0,0,0,0))
227: != SS$_NORMAL) {
228: DEBUG(7, "ret status on sense failed on Modem setup=%x<", ret);
229: return CF_DIAL;
230: }
231: }
232: #endif VMSDTR
233: next_fd = -1;
234: alarm(0);
235: if (dcr < 0) {
236: if (errno == EACCES)
237: logent(dev.D_line, "CANT OPEN");
238: DEBUG(4, "OPEN FAILED: errno %d\n", errno);
239: delock(dev.D_line);
240: return CF_DIAL;
241: }
242: fflush(stdout);
243: if (fixline(dcr, dev.D_speed) == FAIL) {
244: DEBUG(4, "FIXLINE FAILED\n", CNULL);
245: return CF_DIAL;
246: }
247: strcpy(devSel, dev.D_line); /* for latter unlock */
248: CU_end = dircls;
249: return dcr;
250: }
251:
252: dircls(fd)
253: register int fd;
254: {
255: if (fd > 0) {
256: close(fd);
257: delock(devSel);
258: }
259: }
260:
261: /*
262: * open an ACU and dial the number. The condevs table
263: * will be searched until a dialing unit is found that is free.
264: *
265: * return codes: >0 - file number - o.k.
266: * FAIL - failed
267: */
268: char devSel[20]; /* used for later unlock() */
269:
270: Acuopn(flds)
271: register char *flds[];
272: {
273: char phone[MAXPH+1];
274: register struct condev *cd;
275: register int fd, acustatus;
276: register FILE *dfp;
277: struct Devices dev;
278: int retval = CF_NODEV;
279: char nobrand[MAXPH], *line;
280:
281: exphone(flds[F_PHONE], phone);
282: if (snccmp(flds[F_LINE], "LOCAL") == SAME)
283: line = "ACU";
284: else
285: line = flds[F_LINE];
286: devSel[0] = '\0';
287: nobrand[0] = '\0';
288: DEBUG(4, "Dialing %s\n", phone);
289: dfp = fopen(DEVFILE, "r");
290: if (dfp == NULL) {
291: syslog(LOG_ERR, "fopen(%s) failed: %m", DEVFILE);
292: cleanup(FAIL);
293: }
294:
295: acustatus = 0; /* none found, none locked */
296: while (rddev(dfp, &dev) != FAIL) {
297: /*
298: * for each ACU L.sys line, try at most twice
299: * (TRYCALLS) to establish carrier. The old way tried every
300: * available dialer, which on big sites takes forever!
301: * Sites with a single auto-dialer get one try.
302: * Sites with multiple dialers get a try on each of two
303: * different dialers.
304: * To try 'harder' to connect to a remote site,
305: * use multiple L.sys entries.
306: */
307: if (acustatus > TRYCALLS)
308: break;
309: if (strcmp(flds[F_CLASS], dev.D_class) != SAME)
310: continue;
311: if (snccmp(line, dev.D_type) != SAME)
312: continue;
313: if (dev.D_brand[0] == '\0') {
314: logent("Acuopn","No 'brand' name on ACU");
315: continue;
316: }
317: for(cd = condevs; cd->CU_meth != NULL; cd++) {
318: if (snccmp(line, cd->CU_meth) == SAME) {
319: if (snccmp(dev.D_brand, cd->CU_brand) == SAME) {
320: nobrand[0] = '\0';
321: break;
322: }
323: strncpy(nobrand, dev.D_brand, sizeof nobrand);
324: }
325: }
326:
327: if (acustatus < 1)
328: acustatus = 1; /* has been found */
329:
330: if (mlock(dev.D_line) == FAIL)
331: continue;
332:
333: #ifdef DIALINOUT
334: #ifdef ALLACUINOUT
335: if (1) {
336: #else !ALLACUINOUT
337: if (snccmp("inout", dev.D_calldev) == SAME) {
338: #endif !ALLACUINOUT
339: if (disable(dev.D_line) == FAIL) {
340: delock(dev.D_line);
341: continue;
342: }
343: } else
344: reenable();
345: #endif DIALINOUT
346:
347: DEBUG(4, "Using %s\n", cd->CU_brand);
348: acustatus++;
349: fd = (*(cd->CU_open))(phone, flds, &dev);
350: if (fd > 0) {
351: CU_end = cd->CU_clos; /* point CU_end at close func */
352: fclose(dfp);
353: strcpy(devSel, dev.D_line); /* save for later unlock() */
354: return fd;
355: } else
356: delock(dev.D_line);
357: retval = CF_DIAL;
358: }
359: fclose(dfp);
360: if (acustatus == 0) {
361: if (nobrand[0])
362: logent(nobrand, "unsupported ACU type");
363: else
364: logent("L-devices", "No appropriate ACU");
365: }
366: if (acustatus == 1)
367: logent("DEVICE", "NO");
368: return retval;
369: }
370:
371: /*
372: * intervaldelay: delay execution for numerator/denominator seconds.
373: */
374:
375: #ifdef INTERVALTIMER
376: #include <sys/time.h>
377: #define uucpdelay(num,denom) intervaldelay(num,denom)
378: intervaldelay(num,denom)
379: int num, denom;
380: {
381: struct timeval tv;
382: tv.tv_sec = num / denom;
383: tv.tv_usec = (num * 1000000L / denom ) % 1000000L;
384: (void) select (0, (int *)0, (int *)0, (int *)0, &tv);
385: }
386: #endif INTERVALTIMER
387:
388: #ifdef FASTTIMER
389: #define uucpdelay(num,denom) nap(60*num/denom)
390: /* Sleep in increments of 60ths of second. */
391: nap (time)
392: register int time;
393: {
394: static int fd;
395:
396: if (fd == 0)
397: fd = open (FASTTIMER, 0);
398:
399: read (fd, 0, time);
400: }
401: #endif FASTTIMER
402:
403: #ifdef FTIME
404: #define uucpdelay(num,denom) ftimedelay(1000*num/denom)
405: ftimedelay(n)
406: {
407: static struct timeb loctime;
408: register i = loctime.millitm;
409:
410: ftime(&loctime);
411: while (abs((int)(loctime.millitm - i))<n) ftime(&loctime)
412: ;
413: }
414: #endif FTIME
415:
416: #ifdef BUSYLOOP
417: #define uucpdelay(num,denom) busyloop(CPUSPEED*num/denom)
418: #define CPUSPEED 1000000 /* VAX 780 is 1MIPS */
419: #define DELAY(n) { register long N = (n); while (--N > 0); }
420: busyloop(n)
421: {
422: DELAY(n);
423: }
424: #endif BUSYLOOP
425:
426: slowrite(fd, str)
427: register char *str;
428: {
429: DEBUG(6, "slowrite ", CNULL);
430: while (*str) {
431: DEBUG(6, "%c", *str);
432: uucpdelay(1, 10); /* delay 1/10 second */
433: write(fd, str, 1);
434: str++;
435: }
436: DEBUG(6, "\n", CNULL);
437: }
438:
439: #define BSPEED B150
440:
441: /*
442: * send a break
443: */
444: genbrk(fn, bnulls)
445: register int fn, bnulls;
446: {
447: #ifdef USG
448: if (ioctl(fn, TCSBRK, STBNULL) < 0)
449: DEBUG(5, "break TCSBRK %s\n", sys_errlist[errno]);
450: #else !USG
451: # ifdef TIOCSBRK
452: if (ioctl(fn, TIOCSBRK, STBNULL) < 0)
453: DEBUG(5, "break TIOCSBRK %s\n", sys_errlist[errno]);
454: # ifdef TIOCCBRK
455: uucpdelay(bnulls, 10);
456: if (ioctl(fn, TIOCCBRK, STBNULL) < 0)
457: DEBUG(5, "break TIOCCBRK %s\n", sys_errlist[errno]);
458: # endif TIOCCBRK
459: DEBUG(4, "ioctl %f second break\n", (float) bnulls/10 );
460: # else !TIOCSBRK
461: struct sgttyb ttbuf;
462: register int sospeed;
463:
464: if (ioctl(fn, TIOCGETP, &ttbuf) < 0)
465: DEBUG(5, "break TIOCGETP %s\n", sys_errlist[errno]);
466: sospeed = ttbuf.sg_ospeed;
467: ttbuf.sg_ospeed = BSPEED;
468: if (ioctl(fn, TIOCSETP, &ttbuf) < 0)
469: DEBUG(5, "break TIOCSETP %s\n", sys_errlist[errno]);
470: if (write(fn, "\0\0\0\0\0\0\0\0\0\0\0\0", bnulls) != bnulls) {
471: badbreak:
472: logent(sys_errlist[errno], "BAD WRITE genbrk");
473: alarm(0);
474: longjmp(Sjbuf, 3);
475: }
476: ttbuf.sg_ospeed = sospeed;
477: if (ioctl(fn, TIOCSETP, &ttbuf) < 0)
478: DEBUG(5, "break ioctl %s\n", sys_errlist[errno]);
479: if (write(fn, "@", 1) != 1)
480: goto badbreak;
481: DEBUG(4, "sent BREAK nulls - %d\n", bnulls);
482: #endif !TIOCSBRK
483: #endif !USG
484: }
485:
486:
487: #ifdef DIALINOUT
488: /* DIALIN/OUT CODE (WLS) */
489: /*
490: * disable and reenable: allow a single line to be use for dialin/dialout
491: *
492: */
493:
494: char enbdev[16];
495:
496: disable(dev)
497: register char *dev;
498: {
499: register char *rdev;
500:
501: /* strip off directory prefixes */
502: rdev = dev;
503: while (*rdev)
504: rdev++;
505: while (--rdev >= dev && *rdev != '/')
506: ;
507: rdev++;
508:
509: if (enbdev[0]) {
510: if (strcmp(enbdev, rdev) == SAME)
511: return SUCCESS; /* already disabled */
512: delock(enbdev);
513: reenable(); /* else, reenable the old one */
514: }
515: DEBUG(4, "Disable %s\n", rdev);
516: if (enbcall("disable", rdev) == FAIL)
517: return FAIL;
518: strcpy(enbdev, rdev);
519: return SUCCESS;
520: }
521:
522: reenable()
523: {
524: if (enbdev[0] == '\0')
525: return;
526: DEBUG(4, "Reenable %s\n", enbdev);
527: (void) enbcall("enable", enbdev);
528: enbdev[0] = '\0';
529: }
530:
531: enbcall(type, dev)
532: char *type, *dev;
533: {
534: int pid;
535: register char *p;
536: int fildes[2];
537: int status;
538: FILE *fil;
539: char buf[80];
540:
541: fflush(stderr);
542: fflush(stdout);
543: pipe(fildes);
544: if ((pid = fork()) == 0) {
545: DEBUG(4, DIALINOUT, CNULL);
546: DEBUG(4, " %s", type);
547: DEBUG(4, " %s\n", dev);
548: close(fildes[0]);
549: close(0); close(1); close(2);
550: open(_PATH_DEVNULL,0);
551: dup(fildes[1]); dup(fildes[1]);
552: setuid(geteuid()); /* for chown(uid()) in acu program */
553: execl(DIALINOUT, "acu", type, dev, Rmtname, (char *)0);
554: exit(-1);
555: }
556: if (pid<0)
557: return FAIL;
558:
559: close(fildes[1]);
560: fil = fdopen(fildes[0],"r");
561: if (fil!=NULL) {
562: #ifdef BSD4_2
563: setlinebuf(fil);
564: #endif BSD4_2
565: while (fgets(buf, sizeof buf, fil) != NULL) {
566: p = buf + strlen(buf) - 1;
567: if (*p == '\n')
568: *p = '\0';
569: DEBUG(4, "ACUCNTRL: %s\n", buf);
570: }
571: }
572: while(wait(&status) != pid)
573: ;
574: fclose(fil);
575: return status ? FAIL : SUCCESS;
576: }
577: #endif DIALINOUT
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.