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