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