xref: /plan9/sys/src/cmd/telco/telco.c (revision 5d459b5a09e427ae1acd4e6afcf028853c73946e)
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