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