1 #include <u.h> 2 #include <libc.h> 3 #include <auth.h> 4 #include <fcall.h> 5 #include <lock.h> 6 7 #define LOGFILE "telco" 8 9 /* 10 * Rather than reading /adm/users, which is a lot of work for 11 * a toy progdev, we assume all groups have the form 12 * NNN:user:user: 13 * meaning that each user is the leader of his own group. 14 */ 15 16 enum 17 { 18 OPERM = 0x3, /* mask of all permission types in open mode */ 19 Ndev = 8, 20 Nreq = (Ndev*3)/2, 21 Nrbuf = 32*1024, 22 }; 23 24 typedef struct Fid Fid; 25 typedef struct Dev Dev; 26 typedef struct Request Request; 27 typedef struct Type Type; 28 29 struct Fid 30 { 31 Qid qid; 32 short busy; 33 short open; 34 int fid; 35 Fid *next; 36 char *user; 37 }; 38 39 struct Request 40 { 41 Request *next; 42 43 Fid *fid; 44 ulong tag; 45 int count; 46 int flushed; 47 }; 48 49 struct Dev 50 { 51 Lock; 52 53 /* device state */ 54 int ctl; /* control fd */ 55 int data; /* data fd */ 56 char *path; /* to device */ 57 Type *t; 58 Type *baset; 59 int speed; 60 int fclass; 61 62 /* fs emulation */ 63 int open; 64 long perm; 65 char name[NAMELEN]; 66 char user[NAMELEN]; 67 char msgbuf[128]; 68 Request *r; 69 Request *rlast; 70 71 /* input reader */ 72 int monitoring; /* monitor pid */ 73 char rbuf[Nrbuf]; 74 char *rp; 75 char *wp; 76 long pid; 77 }; 78 79 enum 80 { 81 Devmask= (Ndev-1)<<8, 82 83 Qlvl1= 0, 84 Qlvl2= 1, 85 Qclone= 2, 86 Qlvl3= 3, 87 Qdata= 4, 88 Qctl= 5, 89 90 Pexec = 1, 91 Pwrite = 2, 92 Pread = 4, 93 Pother = 1, 94 Pgroup = 8, 95 Powner = 64, 96 }; 97 98 char *names[] = 99 { 100 [Qlvl1] "/", 101 [Qlvl2] "telco", 102 [Qclone] "clone", 103 [Qlvl3] "", 104 [Qdata] "data", 105 [Qctl] "ctl", 106 }; 107 108 #define DEV(q) (((q).path&Devmask)>>8) 109 #define TYPE(q) ((q).path&((1<<8)-1)) 110 #define MKQID(t, i) ((((i)<<8)&Devmask) | (t)) 111 112 enum 113 { 114 /* 115 * modem specific commands 116 */ 117 Cerrorcorrection = 0, /* error correction */ 118 Ccompression, /* compression */ 119 Cflowctl, /* CTS/RTS */ 120 Crateadjust, /* follow line speed */ 121 Cfclass2, /* set up for fax */ 122 Cfclass0, /* set up for data */ 123 Ncommand, 124 }; 125 126 struct Type 127 { 128 char *name; 129 char *ident; /* inquire request */ 130 char *response; /* inquire response (strstr) */ 131 char *basetype; /* name of base type */ 132 133 char *commands[Ncommand]; 134 }; 135 136 /* 137 * Fax setup summary 138 * 139 * FCLASS=2 - set to service class 2, i.e., one where the fax handles timing 140 * FTBC=0 - ??? 141 * FREL=1 - ??? 142 * FCQ=1 - receive copy quality checking enabled 143 * FBOR=1 - set reversed bit order for phase C data 144 * FCR=1 - the DCE can receive message data, bit 10 in the DIS or 145 * DTC frame will be set 146 * FDIS=,3 - limit com speed to 9600 baud 147 */ 148 149 Type typetab[] = 150 { 151 { "Rockwell", 0, 0, 0, 152 "AT\\N7", /* auto reliable (V.42, fall back to MNP, to none) */ 153 "AT%C1\\J0", /* negotiate for compression, don't change port baud rate */ 154 "AT\\Q3", /* CTS/RTS flow control */ 155 "AT\\J1", 156 "AT+FCLASS=2\rAT+FCR=1\r", 157 "AT+FCLASS=0", 158 }, 159 160 { "ATT2400", "ATI9", "E2400", "Rockwell", 161 "AT\\N3", /* auto reliable (MNP, fall back to none) */ 162 0, 163 0, 164 0, 165 0, 166 0, 167 }, 168 169 { "ATT14400", "ATI9", "E14400", "Rockwell", 170 0, 171 0, 172 0, 173 0, 174 0, 175 0, 176 }, 177 178 { "MT1432", "ATI2", "MT1432", 0, 179 "AT&E1", /* auto reliable (V.42, fall back to none) */ 180 "AT&E15$BA0", /* negotiate for compression */ 181 "AT&E4", /* CTS/RTS flow control */ 182 "AT$BA1", /* don't change port baud rate */ 183 "AT+FCLASS=2\rAT+FTBC=0\rAT+FREL=1\rAT+FCQ=1\rAT+FBOR=1\rAT+FCR=1\rAT+FDIS=,3", 184 "AT+FCLASS=0", 185 }, 186 187 { "MT2834", "ATI2", "MT2834", "MT1432", 188 0, 189 0, 190 0, 191 0, 192 "AT+FCLASS=2\rAT+FTBC=0\rAT+FREL=1\rAT+FCQ=1\rAT+FBOR=1\rAT+FCR=1", 193 0, 194 }, 195 196 { "VOCAL", "ATI6", "144DPL+FAX", "Rockwell", 197 "AT\\N3", /* auto reliable (V.42, fall back to MNP, fall back to none) */ 198 "AT%C3\\J0", /* negotiate for compression, don't change port baud rate */ 199 0, 200 0, 201 "AT+FCLASS=2\rAT+FTBC=0\rAT+FREL=1\rAT+FCQ=1\rAT+FBOR=1\rAT+FCR=1", 202 "AT+FCLASS=0", 203 }, 204 205 { 0, }, 206 }; 207 208 /* 209 * modem return codes 210 */ 211 enum 212 { 213 Ok, 214 Success, 215 Failure, 216 Noise, 217 Found, 218 }; 219 220 /* 221 * modem return messages 222 */ 223 typedef struct Msg Msg; 224 struct Msg 225 { 226 char *text; 227 int type; 228 }; 229 230 Msg msgs[] = 231 { 232 { "OK", Ok, }, 233 { "NO CARRIER", Failure, }, 234 { "ERROR", Failure, }, 235 { "NO DIALTONE", Failure, }, 236 { "BUSY", Failure, }, 237 { "NO ANSWER", Failure, }, 238 { "CONNECT", Success, }, 239 { 0, 0 }, 240 }; 241 242 Fid *fids; 243 Dev *dev; 244 int ndev; 245 int mfd[2]; 246 char user[NAMELEN]; 247 char mdata[MAXMSG+MAXFDATA]; 248 Fcall rhdr; 249 Fcall thdr; 250 char errbuf[ERRLEN+1]; 251 int pulsed; 252 int verbose; 253 int maxspeed = 56000; 254 char *srcid = "plan9"; 255 256 Fid *newfid(int); 257 void devstat(Dir*, char*); 258 int devgen(Qid, int, Dir*, char*); 259 void error(char*); 260 void io(void); 261 void *erealloc(void*, ulong); 262 void *emalloc(ulong); 263 void usage(void); 264 int perm(Fid*, Dev*, int); 265 void setspeed(Dev*, int); 266 int getspeed(char*, int); 267 char *dialout(Dev*, char*); 268 void onhook(Dev*); 269 int readmsg(Dev*, int, char*); 270 void monitor(Dev*); 271 int getinput(Dev*, char*, int); 272 void serve(Dev*); 273 void receiver(Dev*); 274 char* modemtype(Dev*, int, int); 275 276 277 char *rflush(Fid*), *rnop(Fid*), *rsession(Fid*), 278 *rattach(Fid*), *rclone(Fid*), *rwalk(Fid*), 279 *rclwalk(Fid*), *ropen(Fid*), *rcreate(Fid*), 280 *rread(Fid*), *rwrite(Fid*), *rclunk(Fid*), 281 *rremove(Fid*), *rstat(Fid*), *rwstat(Fid*), 282 *rauth(Fid*); 283 284 char *(*fcalls[])(Fid*) = { 285 [Tflush] rflush, 286 [Tsession] rsession, 287 [Tnop] rnop, 288 [Tattach] rattach, 289 [Tclone] rclone, 290 [Twalk] rwalk, 291 [Tclwalk] rclwalk, 292 [Topen] ropen, 293 [Tcreate] rcreate, 294 [Tread] rread, 295 [Twrite] rwrite, 296 [Tclunk] rclunk, 297 [Tremove] rremove, 298 [Tstat] rstat, 299 [Twstat] rwstat, 300 }; 301 302 char Eperm[] = "permission denied"; 303 char Enotdir[] = "not a directory"; 304 char Enotexist[] = "file does not exist"; 305 char Eio[] = "i/o error"; 306 char Ebadaddr[] = "bad address"; 307 char Eattn[] = "can't get modem's attention"; 308 char Edial[] = "can't dial"; 309 char Enoauth[] = "authentication not implimented"; 310 char Eisopen[] = "file already open for I/O"; 311 char Enodev[] = "no free modems"; 312 char Enostream[] = "stream closed prematurely"; 313 314 void 315 usage(void) 316 { 317 fprint(2, "usage: %s [-vp] [-i srcid] dev ...\n", argv0); 318 exits("usage"); 319 } 320 321 void 322 notifyf(void *a, char *s) 323 { 324 USED(a); 325 if(strncmp(s, "interrupt", 9) == 0) 326 noted(NCONT); 327 noted(NDFLT); 328 } 329 330 void 331 main(int argc, char *argv[]) 332 { 333 int p[2]; 334 int fd; 335 char buf[10]; 336 Dev *d; 337 338 ARGBEGIN{ 339 case 'p': 340 pulsed = 1; 341 break; 342 case 'v': 343 verbose = 1; 344 break; 345 case 'i': 346 srcid = ARGF(); 347 break; 348 case 's': 349 maxspeed = atoi(ARGF()); 350 break; 351 default: 352 usage(); 353 }ARGEND 354 355 if(argc == 0) 356 usage(); 357 if(argc > Ndev) 358 argc = Ndev; 359 360 if(pipe(p) < 0) 361 error("pipe failed"); 362 363 notify(notifyf); 364 fmtinstall('F', fcallconv); 365 strcpy(user, getuser()); 366 367 switch(rfork(RFFDG|RFPROC|RFNAMEG|RFNOTEG)){ 368 case -1: 369 error("fork"); 370 case 0: 371 close(p[1]); 372 mfd[0] = mfd[1] = p[0]; 373 break; 374 default: 375 close(p[0]); 376 fd = create("/srv/telco", OWRITE, 0666); 377 if(fd < 0) 378 error("create of /srv/telco failed"); 379 sprint(buf, "%d", p[1]); 380 if(write(fd, buf, strlen(buf)) < 0) 381 error("writing /srv/telco"); 382 close(fd); 383 if(amount(p[1], "/net", MBEFORE, "") < 0) 384 error("mount failed"); 385 exits(0); 386 } 387 388 lockinit(); 389 390 dev = malloc(argc*sizeof(Dev)); 391 for(ndev = 0; ndev < argc; ndev++){ 392 d = &dev[ndev]; 393 d->path = argv[ndev]; 394 d->rp = d->wp = d->rbuf; 395 monitor(d); 396 d->open++; 397 onhook(d); 398 d->open--; 399 } 400 401 io(); 402 } 403 404 /* 405 * generate a stat structure for a qid 406 */ 407 void 408 devstat(Dir *dir, char *buf) 409 { 410 Dev *d; 411 int t; 412 413 memset(dir->name, 0, sizeof(dir->name)); 414 memset(dir->uid, 0, sizeof(dir->uid)); 415 memset(dir->gid, 0, sizeof(dir->gid)); 416 t = TYPE(dir->qid); 417 if(t != Qlvl3) 418 strcpy(dir->name, names[t]); 419 else 420 sprint(dir->name, "%d", DEV(dir->qid)); 421 dir->mode = 0755; 422 strcpy(dir->uid, user); 423 if(t >= Qlvl3){ 424 d = &dev[DEV(dir->qid)]; 425 if(d->open){ 426 dir->mode = d->perm; 427 strcpy(dir->uid, d->user); 428 } 429 } 430 if(dir->qid.path & CHDIR) 431 dir->mode |= CHDIR; 432 strcpy(dir->gid, user); 433 dir->hlength = 0; 434 if(t == Qdata){ 435 d = &dev[DEV(dir->qid)]; 436 dir->length = d->wp - d->rp; 437 if(dir->length < 0) 438 dir->length += Nrbuf; 439 } else 440 dir->length = 0; 441 dir->atime = time(0); 442 dir->mtime = dir->atime; 443 if(buf) 444 convD2M(dir, buf); 445 } 446 447 /* 448 * enumerate file's we can walk to from q 449 */ 450 int 451 devgen(Qid q, int i, Dir *d, char *buf) 452 { 453 static ulong v; 454 455 d->qid.vers = v++; 456 switch(TYPE(q)){ 457 case Qlvl1: 458 if(i != 0) 459 return -1; 460 d->qid.path = CHDIR|Qlvl2; 461 break; 462 case Qlvl2: 463 switch(i){ 464 case -1: 465 d->qid.path = CHDIR|Qlvl1; 466 break; 467 case 0: 468 d->qid.path = Qclone; 469 break; 470 default: 471 if(i > ndev) 472 return -1; 473 d->qid.path = MKQID(CHDIR|Qlvl3, i-1); 474 break; 475 } 476 break; 477 case Qlvl3: 478 switch(i){ 479 case -1: 480 d->qid.path = CHDIR|Qlvl2; 481 break; 482 case 0: 483 d->qid.path = MKQID(Qdata, DEV(q)); 484 break; 485 case 1: 486 d->qid.path = MKQID(Qctl, DEV(q)); 487 break; 488 default: 489 return -1; 490 } 491 break; 492 default: 493 return -1; 494 } 495 devstat(d, buf); 496 return 0; 497 } 498 499 char* 500 rnop(Fid *f) 501 { 502 USED(f); 503 return 0; 504 } 505 506 char* 507 rsession(Fid *unused) 508 { 509 Fid *f; 510 511 USED(unused); 512 513 for(f = fids; f; f = f->next) 514 if(f->busy) 515 rclunk(f); 516 memset(thdr.authid, 0, sizeof(thdr.authid)); 517 memset(thdr.authdom, 0, sizeof(thdr.authdom)); 518 memset(thdr.chal, 0, sizeof(thdr.chal)); 519 return 0; 520 } 521 522 char* 523 rflush(Fid *f) 524 { 525 Request *r, **l; 526 Dev *d; 527 528 USED(f); 529 for(d = dev; d < &dev[ndev]; d++){ 530 lock(d); 531 for(l = &d->r; r = *l; l = &r->next) 532 if(r->tag == rhdr.oldtag){ 533 *l = r->next; 534 free(r); 535 break; 536 } 537 unlock(d); 538 } 539 return 0; 540 } 541 542 char * 543 rauth(Fid *f) 544 { 545 USED(f); 546 return Enoauth; 547 } 548 549 char* 550 rattach(Fid *f) 551 { 552 f->busy = 1; 553 f->qid.path = CHDIR | Qlvl1; 554 f->qid.vers = 0; 555 thdr.qid = f->qid; 556 if(rhdr.uname[0]) 557 f->user = strdup(rhdr.uname); 558 else 559 f->user = "none"; 560 return 0; 561 } 562 563 char* 564 rclone(Fid *f) 565 { 566 Fid *nf; 567 568 if(f->open) 569 return Eisopen; 570 if(f->busy == 0) 571 return Enotexist; 572 nf = newfid(rhdr.newfid); 573 nf->busy = 1; 574 nf->open = 0; 575 nf->qid = f->qid; 576 nf->user = strdup(f->user); 577 return 0; 578 } 579 580 char* 581 rwalk(Fid *f) 582 { 583 int i; 584 char *name; 585 Dir dir; 586 587 if((f->qid.path & CHDIR) == 0) 588 return Enotdir; 589 name = rhdr.name; 590 if(strcmp(name, ".") == 0) 591 dir.qid = f->qid; 592 else if(strcmp(name, "..") == 0){ 593 if(devgen(f->qid, -1, &dir, 0) < 0) 594 return Enotexist; 595 } else for(i = 0;; i++){ 596 if(devgen(f->qid, i, &dir, 0) < 0) 597 return Enotexist; 598 if(strcmp(name, dir.name) == 0) 599 break; 600 } 601 f->qid = dir.qid; 602 thdr.qid = f->qid; 603 return 0; 604 } 605 606 char * 607 rclwalk(Fid *f) 608 { 609 Fid *nf; 610 char *err; 611 612 nf = newfid(rhdr.newfid); 613 nf->busy = 1; 614 nf->qid = f->qid; 615 nf->user = strdup(f->user); 616 if(err = rwalk(nf)) 617 rclunk(nf); 618 return err; 619 } 620 621 char * 622 ropen(Fid *f) 623 { 624 Dev *d; 625 int mode, t; 626 627 if(f->open) 628 return Eisopen; 629 mode = rhdr.mode; 630 mode &= OPERM; 631 if(f->qid.path & CHDIR){ 632 if(mode != OREAD) 633 return Eperm; 634 thdr.qid = f->qid; 635 return 0; 636 } 637 if(mode==OEXEC) 638 return Eperm; 639 t = TYPE(f->qid); 640 if(t == Qclone){ 641 for(d = dev; d < &dev[ndev]; d++) 642 if(d->open == 0) 643 break; 644 if(d == &dev[ndev]) 645 return Enodev; 646 f->qid.path = MKQID(Qctl, d-dev); 647 t = Qctl; 648 } 649 switch(t){ 650 case Qdata: 651 case Qctl: 652 d = &dev[DEV(f->qid)]; 653 if(d->open == 0){ 654 strcpy(d->user, f->user); 655 d->perm = 0660; 656 }else { 657 if(mode==OWRITE || mode==ORDWR) 658 if(!perm(f, d, Pwrite)) 659 return Eperm; 660 if(mode==OREAD || mode==ORDWR) 661 if(!perm(f, d, Pread)) 662 return Eperm; 663 } 664 d->open++; 665 break; 666 } 667 thdr.qid = f->qid; 668 f->open = 1; 669 return 0; 670 } 671 672 char * 673 rcreate(Fid *f) 674 { 675 USED(f); 676 return Eperm; 677 } 678 679 /* 680 * intercept a note 681 */ 682 void 683 takeanote(void *u, char *note) 684 { 685 USED(u); 686 if(strstr(note, "flushed")) 687 noted(NCONT); 688 noted(NDFLT); 689 } 690 691 char* 692 rread(Fid *f) 693 { 694 char *buf; 695 long off; 696 int i, n, cnt, t; 697 Dir dir; 698 char num[32]; 699 Dev *d; 700 Request *r; 701 702 n = 0; 703 thdr.count = 0; 704 off = rhdr.offset; 705 cnt = rhdr.count; 706 buf = thdr.data; 707 t = TYPE(f->qid); 708 switch(t){ 709 default: 710 cnt = (cnt/DIRLEN)*DIRLEN; 711 if(off%DIRLEN) 712 return Eio; 713 for(i = off/DIRLEN; n < cnt; i++){ 714 if(devgen(f->qid, i, &dir, buf+n) < 0) 715 break; 716 n += DIRLEN; 717 } 718 break; 719 case Qctl: 720 i = sprint(num, "%d", DEV(f->qid)); 721 if(off < i){ 722 n = cnt; 723 if(off + n > i) 724 n = i - off; 725 memmove(buf, num + off, n); 726 } else 727 n = 0; 728 break; 729 case Qdata: 730 d = &dev[DEV(f->qid)]; 731 r = malloc(sizeof(Request)); 732 r->tag = rhdr.tag; 733 r->count = rhdr.count; 734 r->fid = f; 735 r->flushed = 0; 736 lock(d); 737 if(d->r) 738 d->rlast->next = r; 739 else 740 d->r = r; 741 d->rlast = r; 742 serve(d); 743 unlock(d); 744 return ""; 745 } 746 thdr.count = n; 747 return 0; 748 } 749 750 char *cmsg = "connect "; 751 int clen; 752 753 char* 754 rwrite(Fid *f) 755 { 756 Dev *d; 757 ulong off; 758 int cnt; 759 char *cp; 760 char buf[64]; 761 762 off = rhdr.offset; 763 cnt = rhdr.count; 764 switch(TYPE(f->qid)){ 765 default: 766 return "file is a directory"; 767 case Qctl: 768 d = &dev[DEV(f->qid)]; 769 clen = strlen(cmsg); 770 if(cnt < clen || strncmp(rhdr.data, cmsg, clen) != 0){ 771 /* 772 * send control message to real control file 773 */ 774 if(seek(d->ctl, off, 0) < 0 || write(d->ctl, rhdr.data, cnt) < 0){ 775 errstr(errbuf); 776 return errbuf; 777 } 778 } else { 779 /* 780 * connect 781 */ 782 cnt -= clen; 783 if(cnt >= sizeof(buf)) 784 cnt = sizeof(buf) - 1; 785 if(cnt < 0) 786 return Ebadaddr; 787 strncpy(buf, &rhdr.data[clen], cnt); 788 buf[cnt] = 0; 789 cp = dialout(d, buf); 790 if(cp) 791 return cp; 792 } 793 thdr.count = cnt; 794 break; 795 case Qdata: 796 d = &dev[DEV(f->qid)]; 797 if(write(d->data, rhdr.data, cnt) < 0){ 798 errstr(errbuf); 799 return errbuf; 800 } 801 thdr.count = cnt; 802 break; 803 } 804 return 0; 805 } 806 807 char * 808 rclunk(Fid *f) 809 { 810 Dev *d; 811 812 if(f->open) 813 switch(TYPE(f->qid)){ 814 case Qdata: 815 case Qctl: 816 d = &dev[DEV(f->qid)]; 817 if(d->open == 1) 818 onhook(d); 819 d->open--; 820 break; 821 } 822 free(f->user); 823 f->busy = 0; 824 f->open = 0; 825 return 0; 826 } 827 828 char * 829 rremove(Fid *f) 830 { 831 USED(f); 832 return Eperm; 833 } 834 835 char * 836 rstat(Fid *f) 837 { 838 Dir d; 839 840 d.qid = f->qid; 841 devstat(&d, thdr.stat); 842 return 0; 843 } 844 845 char * 846 rwstat(Fid *f) 847 { 848 Dev *d; 849 Dir dir; 850 851 if(TYPE(f->qid) < Qlvl3) 852 return Eperm; 853 854 convM2D(rhdr.stat, &dir); 855 d = &dev[DEV(f->qid)]; 856 857 /* 858 * To change mode, must be owner 859 */ 860 if(d->perm != dir.mode){ 861 if(strcmp(f->user, d->user) != 0) 862 if(strcmp(f->user, user) != 0) 863 return Eperm; 864 } 865 866 /* all ok; do it */ 867 d->perm = dir.mode & ~CHDIR; 868 return 0; 869 } 870 871 Fid * 872 newfid(int fid) 873 { 874 Fid *f, *ff; 875 876 ff = 0; 877 for(f = fids; f; f = f->next) 878 if(f->fid == fid) 879 return f; 880 else if(!ff && !f->busy) 881 ff = f; 882 if(ff){ 883 ff->fid = fid; 884 return ff; 885 } 886 f = emalloc(sizeof *f); 887 f->fid = fid; 888 f->next = fids; 889 fids = f; 890 return f; 891 } 892 893 /* 894 * read fs requests and dispatch them 895 */ 896 void 897 io(void) 898 { 899 char *err; 900 int n; 901 902 for(;;){ 903 /* 904 * reading from a pipe or a network device 905 * will give an error after a few eof reads 906 * however, we cannot tell the difference 907 * between a zero-length read and an interrupt 908 * on the processes writing to us, 909 * so we wait for the error 910 */ 911 n = read9p(mfd[0], mdata, sizeof mdata); 912 if(n == 0) 913 continue; 914 if(n < 0) 915 error("mount read"); 916 if(convM2S(mdata, &rhdr, n) == 0) 917 continue; 918 919 920 thdr.data = mdata + MAXMSG; 921 if(!fcalls[rhdr.type]) 922 err = "bad fcall type"; 923 else 924 err = (*fcalls[rhdr.type])(newfid(rhdr.fid)); 925 if(err){ 926 if(*err == 0) 927 continue; /* assigned to a slave */ 928 thdr.type = Rerror; 929 strncpy(thdr.ename, err, ERRLEN); 930 }else{ 931 thdr.type = rhdr.type + 1; 932 thdr.fid = rhdr.fid; 933 } 934 thdr.tag = rhdr.tag; 935 n = convS2M(&thdr, mdata); 936 if(write9p(mfd[1], mdata, n) != n) 937 error("mount write"); 938 } 939 } 940 941 942 int 943 perm(Fid *f, Dev *d, int p) 944 { 945 if((p*Pother) & d->perm) 946 return 1; 947 if(strcmp(f->user, user)==0 && ((p*Pgroup) & d->perm)) 948 return 1; 949 if(strcmp(f->user, d->user)==0 && ((p*Powner) & d->perm)) 950 return 1; 951 return 0; 952 } 953 954 void 955 error(char *s) 956 { 957 fprint(2, "%s: %s: %r\n", argv0, s); 958 remove("/srv/telco"); 959 postnote(PNGROUP, getpid(), "exit"); 960 exits(s); 961 } 962 963 void * 964 emalloc(ulong n) 965 { 966 void *p; 967 968 p = malloc(n); 969 if(!p) 970 error("out of memory"); 971 return p; 972 } 973 974 void * 975 erealloc(void *p, ulong n) 976 { 977 p = realloc(p, n); 978 if(!p) 979 error("out of memory"); 980 return p; 981 } 982 983 /* 984 * send bytes to modem 985 */ 986 int 987 send(Dev *d, char *x) 988 { 989 if(verbose) 990 syslog(0, LOGFILE, "->%s", x); 991 return write(d->data, x, strlen(x)); 992 } 993 994 /* 995 * apply a string of commands to modem 996 */ 997 int 998 apply(Dev *d, char *s, char *substr, int secs) 999 { 1000 char buf[128]; 1001 char *p; 1002 int c, m; 1003 1004 p = buf; 1005 m = Ok; 1006 while(*s){ 1007 c = *p++ = *s++; 1008 if(c == '\r' || *s == 0){ 1009 if(c != '\r') 1010 *p++ = '\r'; 1011 *p = 0; 1012 if(send(d, buf) < 0) 1013 return Failure; 1014 m = readmsg(d, secs, substr); 1015 p = buf; 1016 } 1017 } 1018 return m; 1019 } 1020 1021 /* 1022 * apply a command type 1023 */ 1024 int 1025 applyspecial(Dev *d, int index) 1026 { 1027 char *cmd; 1028 1029 cmd = d->t->commands[index]; 1030 if(cmd == 0 && d->baset) 1031 cmd = d->baset->commands[index]; 1032 if(cmd == 0) 1033 return Failure; 1034 1035 return apply(d, cmd, 0, 2); 1036 } 1037 1038 /* 1039 * get modem into command mode if it isn't already 1040 */ 1041 int 1042 attention(Dev *d) 1043 { 1044 int i; 1045 1046 for(i = 0; i < 2; i++){ 1047 sleep(250); 1048 if(send(d, "+") < 0) 1049 continue; 1050 sleep(250); 1051 if(send(d, "+") < 0) 1052 continue; 1053 sleep(250); 1054 if(send(d, "+") < 0) 1055 continue; 1056 sleep(250); 1057 readmsg(d, 0, 0); 1058 if(apply(d, "ATZH0", 0, 2) == Ok) 1059 return Ok; 1060 } 1061 return Failure; 1062 } 1063 1064 int portspeed[] = { 56000, 38400, 19200, 14400, 9600, 4800, 2400, 1200, 600, 300, 0 }; 1065 1066 /* 1067 * get the modem's type and speed 1068 */ 1069 char* 1070 modemtype(Dev *d, int limit, int fax) 1071 { 1072 int *p; 1073 Type *t, *bt; 1074 char buf[28]; 1075 1076 d->t = typetab; 1077 d->baset = 0; 1078 1079 /* assume we're at a good speed, try getting attention a few times */ 1080 attention(d); 1081 1082 /* find a common port rate */ 1083 for(p = portspeed; *p; p++){ 1084 if(*p > limit) 1085 continue; 1086 setspeed(d, *p); 1087 if(attention(d) == Ok) 1088 break; 1089 } 1090 if(*p == 0) 1091 return Eattn; 1092 d->speed = *p; 1093 if(verbose) 1094 syslog(0, LOGFILE, "port speed %d", *p); 1095 1096 /* 1097 * basic Hayes commands everyone implements (we hope) 1098 * Q0 = report result codes 1099 * V1 = full word result codes 1100 * E0 = don't echo commands 1101 * M1 = speaker on until on-line 1102 * S0=0 = autoanswer off 1103 */ 1104 if(apply(d, "ATQ0V1E0M1S0=0", 0, 2) != Ok) 1105 return Eattn; 1106 1107 /* find modem type */ 1108 for(t = typetab; t->name; t++){ 1109 if(t->ident == 0 || t->response == 0) 1110 continue; 1111 if(apply(d, t->ident, t->response, 2) == Found) 1112 break; 1113 readmsg(d, 0, 0); 1114 } 1115 readmsg(d, 0, 0); 1116 if(t->name){ 1117 d->t = t; 1118 if(t->basetype){ 1119 for(bt = typetab; bt->name; bt++) 1120 if(strcmp(bt->name, t->basetype) == 0) 1121 break; 1122 if(bt->name) 1123 d->baset = bt; 1124 } 1125 } 1126 if(verbose) 1127 syslog(0, LOGFILE, "modem %s", d->t->name); 1128 1129 /* try setting fax modes */ 1130 d->fclass = 0; 1131 if(fax){ 1132 /* set up fax parameters */ 1133 if(applyspecial(d, Cfclass2) != Failure) 1134 d->fclass = 2; 1135 1136 /* setup a source id */ 1137 if(srcid){ 1138 sprint(buf, "AT+FLID=\"%s\"", srcid); 1139 apply(d, buf, 0, 2); 1140 } 1141 1142 /* allow both data and fax calls in */ 1143 apply(d, "AT+FAA=1", 0, 2); 1144 } else 1145 applyspecial(d, Cfclass0); 1146 return 0; 1147 } 1148 1149 /* 1150 * a process to read input from a modem. 1151 */ 1152 void 1153 monitor(Dev *d) 1154 { 1155 int n; 1156 char *p; 1157 char file[256]; 1158 1159 switch(d->pid = rfork(RFPROC|RFMEM)){ 1160 case -1: 1161 error("out of processes"); 1162 case 0: 1163 break; 1164 default: 1165 return; 1166 } 1167 1168 d->ctl = d->data = -1; 1169 1170 for(;;){ 1171 lock(d); 1172 sprint(file, "%sctl", d->path); 1173 d->ctl = open(file, ORDWR); 1174 if(d->ctl < 0) 1175 error("opening ctl"); 1176 d->data = open(d->path, ORDWR); 1177 if(d->data < 0) 1178 error("opening data"); 1179 d->wp = d->rp = d->rbuf; 1180 unlock(d); 1181 1182 /* wait for ring or off hook */ 1183 while(d->open == 0){ 1184 d->rp = d->rbuf; 1185 p = d->wp; 1186 n = read(d->data, p, 1); 1187 if(n < 1) 1188 continue; 1189 if(p < &d->rbuf[Nrbuf] - 2) 1190 d->wp++; 1191 if(*p == '\r' || *p == '\n'){ 1192 *(p+1) = 0; 1193 if(verbose) 1194 syslog(0, LOGFILE, "<:-%s", d->rp); 1195 if(strncmp(d->rp, "RING", 4) == 0){ 1196 receiver(d); 1197 continue; 1198 } 1199 if(d->open == 0) 1200 d->wp = d->rbuf; 1201 } 1202 } 1203 1204 /* shuttle bytes till on hook */ 1205 while(d->open){ 1206 if(d->wp >= d->rp) 1207 n = &d->rbuf[Nrbuf] - d->wp; 1208 else 1209 n = d->rp - d->wp - 1; 1210 if(n > 0) 1211 n = read(d->data, d->wp, n); 1212 else { 1213 read(d->data, file, sizeof(file)); 1214 continue; 1215 } 1216 if(n < 0) 1217 break; 1218 lock(d); 1219 if(d->wp + n >= &d->rbuf[Nrbuf]) 1220 d->wp = d->rbuf; 1221 else 1222 d->wp += n; 1223 serve(d); 1224 unlock(d); 1225 } 1226 1227 close(d->ctl); 1228 close(d->data); 1229 } 1230 } 1231 1232 /* 1233 * get bytes input by monitor() (only routine that changes d->rp) 1234 */ 1235 int 1236 getinput(Dev *d, char *buf, int n) 1237 { 1238 char *p; 1239 int i; 1240 1241 p = buf; 1242 while(n > 0){ 1243 if(d->wp == d->rp) 1244 break; 1245 if(d->wp < d->rp) 1246 i = &d->rbuf[Nrbuf] - d->rp; 1247 else 1248 i = d->wp - d->rp; 1249 if(i > n) 1250 i = n; 1251 memmove(p, d->rp, i); 1252 if(d->rp + i == &d->rbuf[Nrbuf]) 1253 d->rp = d->rbuf; 1254 else 1255 d->rp += i; 1256 n -= i; 1257 p += i; 1258 } 1259 return p - buf; 1260 } 1261 1262 /* 1263 * fulfill a read request (we assume d is locked) 1264 */ 1265 void 1266 serve(Dev *d) 1267 { 1268 Request *r; 1269 int n; 1270 Fcall thdr; 1271 char mdata[MAXMSG+MAXFDATA]; 1272 char buf[MAXFDATA]; 1273 1274 for(;;){ 1275 if(d->r == 0 || d->rp == d->wp) 1276 return; 1277 r = d->r; 1278 if(r->count > sizeof(buf)) 1279 r->count = sizeof(buf); 1280 1281 n = getinput(d, buf, r->count); 1282 if(n == 0) 1283 return; 1284 d->r = r->next; 1285 1286 thdr.type = Rread; 1287 thdr.fid = r->fid->fid; 1288 thdr.tag = r->tag; 1289 thdr.data = buf; 1290 thdr.count = n; 1291 n = convS2M(&thdr, mdata); 1292 if(write9p(mfd[1], mdata, n) != n) 1293 fprint(2, "telco: error writing\n"); 1294 free(r); 1295 } 1296 } 1297 1298 /* 1299 * dial a number 1300 */ 1301 char* 1302 dialout(Dev *d, char *number) 1303 { 1304 int i, m, compress, rateadjust, speed, fax; 1305 char *err; 1306 char *field[5]; 1307 char dialstr[2*NAMELEN]; 1308 1309 compress = Ok; 1310 rateadjust = Failure; 1311 speed = maxspeed; 1312 fax = Failure; 1313 1314 setfields("!"); 1315 m = getmfields(number, field, 5); 1316 for(i = 1; i < m; i++){ 1317 if(field[i][0] >= '0' && field[i][0] <= '9') 1318 speed = atoi(field[i]); 1319 else if(strcmp(field[i], "nocompress") == 0) 1320 compress = Failure; 1321 else if(strcmp(field[i], "fax") == 0) 1322 fax = Ok; 1323 } 1324 1325 err = modemtype(d, speed, fax == Ok); 1326 if(err) 1327 return err; 1328 1329 /* 1330 * extented Hayes commands, meaning depends on modem (VGA all over again) 1331 */ 1332 if(fax != Ok){ 1333 if(d->fclass != 0) 1334 applyspecial(d, Cfclass0); 1335 applyspecial(d, Cerrorcorrection); 1336 if(compress == Ok) 1337 compress = applyspecial(d, Ccompression); 1338 if(compress != Ok) 1339 rateadjust = applyspecial(d, Crateadjust); 1340 } 1341 applyspecial(d, Cflowctl); 1342 1343 /* dialout */ 1344 sprint(dialstr, "ATD%c%s\r", pulsed ? 'P' : 'T', number); 1345 if(send(d, dialstr) < 0) 1346 return Edial; 1347 if(fax == Ok) 1348 return 0; /* fax sender worries about the rest */ 1349 switch(readmsg(d, 120, 0)){ 1350 case Success: 1351 break; 1352 default: 1353 return d->msgbuf; 1354 } 1355 1356 /* change line rate if not compressing */ 1357 if(rateadjust == Ok) 1358 setspeed(d, getspeed(d->msgbuf, d->speed)); 1359 1360 return 0; 1361 } 1362 1363 /* 1364 * start a receiving process 1365 */ 1366 void 1367 receiver(Dev *d) 1368 { 1369 int fd; 1370 char file[256]; 1371 char *argv[8]; 1372 int argc; 1373 int pfd[2]; 1374 char *prog; 1375 1376 pipe(pfd); 1377 switch(rfork(RFPROC|RFMEM|RFFDG|RFNAMEG)){ 1378 case -1: 1379 return; 1380 case 0: 1381 fd = open("/srv/telco", ORDWR); 1382 if(fd < 0){ 1383 syslog(0, LOGFILE, "can't open telco: %r"); 1384 exits(0); 1385 } 1386 if(mount(fd, "/net", MAFTER, "") < 0){ 1387 syslog(0, LOGFILE, "can't mount: %r"); 1388 exits(0); 1389 } 1390 close(fd); 1391 1392 /* open connection through the file system interface */ 1393 sprint(file, "/net/telco/%d/data", d - dev); 1394 fd = open(file, ORDWR); 1395 if(fd < 0){ 1396 syslog(0, LOGFILE, "can't open %s: %r", file); 1397 exits(0); 1398 } 1399 1400 /* let parent continue */ 1401 close(pfd[0]); 1402 close(pfd[1]); 1403 1404 /* answer the phone and see what flavor call this is */ 1405 prog = "/bin/service/telcodata"; 1406 switch(apply(d, "ATA", "+FCON", 30)){ 1407 case Success: 1408 break; 1409 case Found: 1410 prog = "/bin/service/telcofax"; 1411 break; 1412 default: 1413 syslog(0, LOGFILE, "bad ATA response"); 1414 exits(0); 1415 } 1416 1417 /* fork a receiving process */ 1418 dup(fd, 0); 1419 dup(fd, 1); 1420 close(fd); 1421 argc = 0; 1422 argv[argc++] = strrchr(prog, '/')+1; 1423 argv[argc++] = file; 1424 argv[argc++] = dev->t->name; 1425 argv[argc] = 0; 1426 exec(prog, argv); 1427 syslog(0, LOGFILE, "can't exec %s: %r\n", prog); 1428 exits(0); 1429 default: 1430 /* wait till child gets the device open */ 1431 close(pfd[1]); 1432 read(pfd[0], file, 1); 1433 close(pfd[0]); 1434 break; 1435 } 1436 } 1437 1438 /* 1439 * hang up an connections in progress 1440 */ 1441 void 1442 onhook(Dev *d) 1443 { 1444 write(d->ctl, "d0", 2); 1445 write(d->ctl, "r0", 2); 1446 sleep(250); 1447 write(d->ctl, "r1", 2); 1448 write(d->ctl, "d1", 2); 1449 modemtype(d, maxspeed, 1); 1450 } 1451 1452 /* 1453 * read till we see a message or we time out 1454 */ 1455 int 1456 readmsg(Dev *d, int secs, char *substr) 1457 { 1458 ulong start; 1459 char *p; 1460 int i, len; 1461 Msg *pp; 1462 int found = 0; 1463 1464 p = d->msgbuf; 1465 len = sizeof(d->msgbuf) - 1; 1466 for(start = time(0); time(0) <= start+secs;){ 1467 if(len && d->rp == d->wp){ 1468 sleep(100); 1469 continue; 1470 } 1471 i = getinput(d, p, 1); 1472 if(i == 0) 1473 continue; 1474 if(*p == '\n' || *p == '\r' || len == 0){ 1475 *p = 0; 1476 if(verbose && p != d->msgbuf) 1477 syslog(0, LOGFILE, "<-%s", d->msgbuf); 1478 if(substr && strstr(d->msgbuf, substr)) 1479 found = 1; 1480 for(pp = msgs; pp->text; pp++) 1481 if(strncmp(pp->text, d->msgbuf, strlen(pp->text))==0) 1482 return found ? Found : pp->type; 1483 start = time(0); 1484 p = d->msgbuf; 1485 len = sizeof(d->msgbuf) - 1; 1486 continue; 1487 } 1488 len--; 1489 p++; 1490 } 1491 strcpy(d->msgbuf, "No response from modem"); 1492 return found ? Found : Noise; 1493 } 1494 1495 /* 1496 * get baud rate from a connect message 1497 */ 1498 int 1499 getspeed(char *msg, int speed) 1500 { 1501 char *p; 1502 int s; 1503 1504 p = msg + sizeof("CONNECT") - 1; 1505 while(*p == ' ' || *p == '\t') 1506 p++; 1507 s = atoi(p); 1508 if(s <= 0) 1509 return speed; 1510 else 1511 return s; 1512 } 1513 1514 /* 1515 * set speed and RTS/CTS modem flow control 1516 */ 1517 void 1518 setspeed(Dev *d, int baud) 1519 { 1520 char buf[32]; 1521 1522 if(d->ctl < 0) 1523 return; 1524 sprint(buf, "b%d", baud); 1525 write(d->ctl, buf, strlen(buf)); 1526 write(d->ctl, "m1", 2); 1527 } 1528