1 #ifndef lint 2 static char sccsid[] = "@(#)condevs.c 5.21 (Berkeley) 05/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 578