Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
313
usage(void)
314
{
315
	fprint(2, "usage: %s [-vp] [-i srcid] dev ...\n", argv0);
316
	exits("usage");
317
}
318
 
319
void
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
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
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
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*
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*
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 *
549
rauth(Fid *f)
550
{
551
	USED(f);
552
	return Enoauth;
553
}
554
 
555
char*
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*
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 *
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 *
686
rcreate(Fid *f)
687
{
688
	USED(f);
689
	return Eperm;
690
}
691
 
692
/*
693
 *  intercept a note
694
 */
695
void
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*
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*
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 *
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 *
843
rremove(Fid *f)
844
{
845
	USED(f);
846
	return Eperm;
847
}
848
 
849
char *
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 *
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 *
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
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
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
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 *
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 *
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
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
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
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
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*
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
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
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
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*
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
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
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
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
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
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
}