1 #ifndef lint 2 static char sccsid[] = "@(#)condevs.c 5.20 (Berkeley) 05/04/88"; 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 if (dfp == NULL) { 165 syslog(LOG_ERR, "fopen(%s) failed: %m", DEVFILE); 166 cleanup(FAIL); 167 } 168 while ((status = rddev(dfp, &dev)) != FAIL) { 169 #ifdef VMSDTR /* Modem control on vms(works dtr) */ 170 /* If we find MOD in the device type field we go into action */ 171 if (strcmp(dev.D_type, "MOD") == SAME) { 172 modem_control = 1; 173 DEBUG(7, "Setting Modem control to %d",modem_control); 174 } 175 if (strcmp(flds[F_CLASS], dev.D_class) != SAME) 176 continue; 177 /* 178 * Modem control on vms(works dtr) Take anything in MOD class. 179 * It probably should work differently anyway so we can have 180 * multiple hardwired lines. 181 */ 182 if (!modem_control&&strcmp(flds[F_PHONE], dev.D_line) != SAME) 183 #else !VMSDTR 184 if (strcmp(flds[F_CLASS], dev.D_class) != SAME) 185 continue; 186 if (strcmp(flds[F_PHONE], dev.D_line) != SAME) 187 #endif !VMSDTR 188 continue; 189 if (mlock(dev.D_line) != FAIL) 190 break; 191 } 192 fclose(dfp); 193 if (status == FAIL) { 194 logent("DEVICE", "NO"); 195 return CF_NODEV; 196 } 197 198 sprintf(dcname, "/dev/%s", dev.D_line); 199 if (setjmp(Sjbuf)) { 200 DEBUG(4, "Open timed out\n", CNULL); 201 delock(dev.D_line); 202 return CF_DIAL; 203 } 204 signal(SIGALRM, alarmtr); 205 /* For PC Pursuit, it could take a while to call back */ 206 alarm( strcmp(flds[F_LINE], "PCP") ? 10 : MAXMSGTIME*4 ); 207 getnextfd(); 208 errno = 0; 209 DEBUG(4,"Opening %s\n",dcname); 210 dcr = open(dcname, 2); /* read/write */ 211 #ifdef VMSDTR /* Modem control on vms(works dtr) */ 212 fflush(stdout); 213 if (modem_control) { /* Did we have MOD in the device type field ? */ 214 /* Sense the current terminal setup and save it */ 215 if ((ret = sys$qiow(_$EFN,(fd_fab_pointer[dcr]->fab).fab$l_stv, 216 IO$_SENSEMODE,iosb,0,0,mode,8,0,0,0,0)) 217 != SS$_NORMAL) { 218 DEBUG(7, "ret status on sense failed on Modem sense=%x<", ret); 219 return CF_DIAL; 220 } 221 mode[1] |= TT$M_MODEM; /* Or in modem control(DTR) */ 222 /* Now set the new terminal characteristics */ 223 /* This is temporary and will go away when we let go of it */ 224 if ((ret = sys$qiow(_$EFN,(fd_fab_pointer[dcr]->fab).fab$l_stv, 225 IO$_SETMODE,iosb,0,0,mode,8,0,0,0,0)) 226 != SS$_NORMAL) { 227 DEBUG(7, "ret status on sense failed on Modem setup=%x<", ret); 228 return CF_DIAL; 229 } 230 } 231 #endif VMSDTR 232 next_fd = -1; 233 alarm(0); 234 if (dcr < 0) { 235 if (errno == EACCES) 236 logent(dev.D_line, "CANT OPEN"); 237 DEBUG(4, "OPEN FAILED: errno %d\n", errno); 238 delock(dev.D_line); 239 return CF_DIAL; 240 } 241 fflush(stdout); 242 if (fixline(dcr, dev.D_speed) == FAIL) { 243 DEBUG(4, "FIXLINE FAILED\n", CNULL); 244 return CF_DIAL; 245 } 246 strcpy(devSel, dev.D_line); /* for latter unlock */ 247 CU_end = dircls; 248 return dcr; 249 } 250 251 dircls(fd) 252 register int fd; 253 { 254 if (fd > 0) { 255 close(fd); 256 delock(devSel); 257 } 258 } 259 260 /* 261 * open an ACU and dial the number. The condevs table 262 * will be searched until a dialing unit is found that is free. 263 * 264 * return codes: >0 - file number - o.k. 265 * FAIL - failed 266 */ 267 char devSel[20]; /* used for later unlock() */ 268 269 Acuopn(flds) 270 register char *flds[]; 271 { 272 char phone[MAXPH+1]; 273 register struct condev *cd; 274 register int fd, acustatus; 275 register FILE *dfp; 276 struct Devices dev; 277 int retval = CF_NODEV; 278 char nobrand[MAXPH], *line; 279 280 exphone(flds[F_PHONE], phone); 281 if (snccmp(flds[F_LINE], "LOCAL") == SAME) 282 line = "ACU"; 283 else 284 line = flds[F_LINE]; 285 devSel[0] = '\0'; 286 nobrand[0] = '\0'; 287 DEBUG(4, "Dialing %s\n", phone); 288 dfp = fopen(DEVFILE, "r"); 289 if (dfp == NULL) { 290 syslog(LOG_ERR, "fopen(%s) failed: %m", DEVFILE); 291 cleanup(FAIL); 292 } 293 294 acustatus = 0; /* none found, none locked */ 295 while (rddev(dfp, &dev) != FAIL) { 296 /* 297 * for each ACU L.sys line, try at most twice 298 * (TRYCALLS) to establish carrier. The old way tried every 299 * available dialer, which on big sites takes forever! 300 * Sites with a single auto-dialer get one try. 301 * Sites with multiple dialers get a try on each of two 302 * different dialers. 303 * To try 'harder' to connect to a remote site, 304 * use multiple L.sys entries. 305 */ 306 if (acustatus > TRYCALLS) 307 break; 308 if (strcmp(flds[F_CLASS], dev.D_class) != SAME) 309 continue; 310 if (snccmp(line, dev.D_type) != SAME) 311 continue; 312 if (dev.D_brand[0] == '\0') { 313 logent("Acuopn","No 'brand' name on ACU"); 314 continue; 315 } 316 for(cd = condevs; cd->CU_meth != NULL; cd++) { 317 if (snccmp(line, cd->CU_meth) == SAME) { 318 if (snccmp(dev.D_brand, cd->CU_brand) == SAME) { 319 nobrand[0] = '\0'; 320 break; 321 } 322 strncpy(nobrand, dev.D_brand, sizeof nobrand); 323 } 324 } 325 326 if (acustatus < 1) 327 acustatus = 1; /* has been found */ 328 329 if (mlock(dev.D_line) == FAIL) 330 continue; 331 332 #ifdef DIALINOUT 333 #ifdef ALLACUINOUT 334 if (1) { 335 #else !ALLACUINOUT 336 if (snccmp("inout", dev.D_calldev) == SAME) { 337 #endif !ALLACUINOUT 338 if (disable(dev.D_line) == FAIL) { 339 delock(dev.D_line); 340 continue; 341 } 342 } else 343 reenable(); 344 #endif DIALINOUT 345 346 DEBUG(4, "Using %s\n", cd->CU_brand); 347 acustatus++; 348 fd = (*(cd->CU_open))(phone, flds, &dev); 349 if (fd > 0) { 350 CU_end = cd->CU_clos; /* point CU_end at close func */ 351 fclose(dfp); 352 strcpy(devSel, dev.D_line); /* save for later unlock() */ 353 return fd; 354 } else 355 delock(dev.D_line); 356 retval = CF_DIAL; 357 } 358 fclose(dfp); 359 if (acustatus == 0) { 360 if (nobrand[0]) 361 logent(nobrand, "unsupported ACU type"); 362 else 363 logent("L-devices", "No appropriate ACU"); 364 } 365 if (acustatus == 1) 366 logent("DEVICE", "NO"); 367 return retval; 368 } 369 370 /* 371 * intervaldelay: delay execution for numerator/denominator seconds. 372 */ 373 374 #ifdef INTERVALTIMER 375 #include <sys/time.h> 376 #define uucpdelay(num,denom) intervaldelay(num,denom) 377 intervaldelay(num,denom) 378 int num, denom; 379 { 380 struct timeval tv; 381 tv.tv_sec = num / denom; 382 tv.tv_usec = (num * 1000000L / denom ) % 1000000L; 383 (void) select (0, (int *)0, (int *)0, (int *)0, &tv); 384 } 385 #endif INTERVALTIMER 386 387 #ifdef FASTTIMER 388 #define uucpdelay(num,denom) nap(60*num/denom) 389 /* Sleep in increments of 60ths of second. */ 390 nap (time) 391 register int time; 392 { 393 static int fd; 394 395 if (fd == 0) 396 fd = open (FASTTIMER, 0); 397 398 read (fd, 0, time); 399 } 400 #endif FASTTIMER 401 402 #ifdef FTIME 403 #define uucpdelay(num,denom) ftimedelay(1000*num/denom) 404 ftimedelay(n) 405 { 406 static struct timeb loctime; 407 register i = loctime.millitm; 408 409 ftime(&loctime); 410 while (abs((int)(loctime.millitm - i))<n) ftime(&loctime) 411 ; 412 } 413 #endif FTIME 414 415 #ifdef BUSYLOOP 416 #define uucpdelay(num,denom) busyloop(CPUSPEED*num/denom) 417 #define CPUSPEED 1000000 /* VAX 780 is 1MIPS */ 418 #define DELAY(n) { register long N = (n); while (--N > 0); } 419 busyloop(n) 420 { 421 DELAY(n); 422 } 423 #endif BUSYLOOP 424 425 slowrite(fd, str) 426 register char *str; 427 { 428 DEBUG(6, "slowrite ", CNULL); 429 while (*str) { 430 DEBUG(6, "%c", *str); 431 uucpdelay(1, 10); /* delay 1/10 second */ 432 write(fd, str, 1); 433 str++; 434 } 435 DEBUG(6, "\n", CNULL); 436 } 437 438 #define BSPEED B150 439 440 /* 441 * send a break 442 */ 443 genbrk(fn, bnulls) 444 register int fn, bnulls; 445 { 446 #ifdef USG 447 if (ioctl(fn, TCSBRK, STBNULL) < 0) 448 DEBUG(5, "break TCSBRK %s\n", sys_errlist[errno]); 449 #else !USG 450 # ifdef TIOCSBRK 451 if (ioctl(fn, TIOCSBRK, STBNULL) < 0) 452 DEBUG(5, "break TIOCSBRK %s\n", sys_errlist[errno]); 453 # ifdef TIOCCBRK 454 uucpdelay(bnulls, 10); 455 if (ioctl(fn, TIOCCBRK, STBNULL) < 0) 456 DEBUG(5, "break TIOCCBRK %s\n", sys_errlist[errno]); 457 # endif TIOCCBRK 458 DEBUG(4, "ioctl %f second break\n", (float) bnulls/10 ); 459 # else !TIOCSBRK 460 struct sgttyb ttbuf; 461 register int sospeed; 462 463 if (ioctl(fn, TIOCGETP, &ttbuf) < 0) 464 DEBUG(5, "break TIOCGETP %s\n", sys_errlist[errno]); 465 sospeed = ttbuf.sg_ospeed; 466 ttbuf.sg_ospeed = BSPEED; 467 if (ioctl(fn, TIOCSETP, &ttbuf) < 0) 468 DEBUG(5, "break TIOCSETP %s\n", sys_errlist[errno]); 469 if (write(fn, "\0\0\0\0\0\0\0\0\0\0\0\0", bnulls) != bnulls) { 470 badbreak: 471 logent(sys_errlist[errno], "BAD WRITE genbrk"); 472 alarm(0); 473 longjmp(Sjbuf, 3); 474 } 475 ttbuf.sg_ospeed = sospeed; 476 if (ioctl(fn, TIOCSETP, &ttbuf) < 0) 477 DEBUG(5, "break ioctl %s\n", sys_errlist[errno]); 478 if (write(fn, "@", 1) != 1) 479 goto badbreak; 480 DEBUG(4, "sent BREAK nulls - %d\n", bnulls); 481 #endif !TIOCSBRK 482 #endif !USG 483 } 484 485 486 #ifdef DIALINOUT 487 /* DIALIN/OUT CODE (WLS) */ 488 /* 489 * disable and reenable: allow a single line to be use for dialin/dialout 490 * 491 */ 492 493 char enbdev[16]; 494 495 disable(dev) 496 register char *dev; 497 { 498 register char *rdev; 499 500 /* strip off directory prefixes */ 501 rdev = dev; 502 while (*rdev) 503 rdev++; 504 while (--rdev >= dev && *rdev != '/') 505 ; 506 rdev++; 507 508 if (enbdev[0]) { 509 if (strcmp(enbdev, rdev) == SAME) 510 return SUCCESS; /* already disabled */ 511 delock(enbdev); 512 reenable(); /* else, reenable the old one */ 513 } 514 DEBUG(4, "Disable %s\n", rdev); 515 if (enbcall("disable", rdev) == FAIL) 516 return FAIL; 517 strcpy(enbdev, rdev); 518 return SUCCESS; 519 } 520 521 reenable() 522 { 523 if (enbdev[0] == '\0') 524 return; 525 DEBUG(4, "Reenable %s\n", enbdev); 526 (void) enbcall("enable", enbdev); 527 enbdev[0] = '\0'; 528 } 529 530 enbcall(type, dev) 531 char *type, *dev; 532 { 533 int pid; 534 register char *p; 535 int fildes[2]; 536 int status; 537 FILE *fil; 538 char buf[80]; 539 540 fflush(stderr); 541 fflush(stdout); 542 pipe(fildes); 543 if ((pid = fork()) == 0) { 544 DEBUG(4, DIALINOUT, CNULL); 545 DEBUG(4, " %s", type); 546 DEBUG(4, " %s\n", dev); 547 close(fildes[0]); 548 close(0); close(1); close(2); 549 open("/dev/null",0); 550 dup(fildes[1]); dup(fildes[1]); 551 setuid(geteuid()); /* for chown(uid()) in acu program */ 552 execl(DIALINOUT, "acu", type, dev, Rmtname, (char *)0); 553 exit(-1); 554 } 555 if (pid<0) 556 return FAIL; 557 558 close(fildes[1]); 559 fil = fdopen(fildes[0],"r"); 560 if (fil!=NULL) { 561 #ifdef BSD4_2 562 setlinebuf(fil); 563 #endif BSD4_2 564 while (fgets(buf, sizeof buf, fil) != NULL) { 565 p = buf + strlen(buf) - 1; 566 if (*p == '\n') 567 *p = '\0'; 568 DEBUG(4, "ACUCNTRL: %s\n", buf); 569 } 570 } 571 while(wait(&status) != pid) 572 ; 573 fclose(fil); 574 return status ? FAIL : SUCCESS; 575 } 576 #endif DIALINOUT 577