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