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 <bio.h>
4
#include <ip.h>
5
 
6
#define	LOG	"pptpd"
7
 
8
typedef struct Call	Call;
9
typedef struct Event Event;
10
 
11
#define	SDB	if(debug) fprint(2, 
12
#define EDB	);
13
 
14
enum {
15
	Magic	= 0x1a2b3c4d,
16
	Nhash	= 17,
17
	Nchan	= 10,		/* maximum number of channels */
18
	Window	= 8,		/* default window size */
19
	Timeout	= 60,		/* timeout in seconds for control channel */
20
	Pktsize = 2000,		/* maximum packet size */
21
	Tick	= 500,		/* tick length in milliseconds */
22
	Sendtimeout = 4,	/* in ticks */
23
};
24
 
25
enum {
26
	Syncframe	= 0x1,
27
	Asyncframe	= 0x2,
28
	Analog		= 0x1,
29
	Digital		= 0x2,
30
	Version		= 0x100,
31
};
32
 
33
enum {
34
	Tstart		= 1,
35
	Rstart		= 2,
36
	Tstop		= 3,
37
	Rstop		= 4,
38
	Techo		= 5,
39
	Recho		= 6,
40
	Tcallout	= 7,
41
	Rcallout	= 8,
42
	Tcallreq	= 9,
43
	Rcallreq	= 10,
44
	Acallcon	= 11,
45
	Tcallclear	= 12,
46
	Acalldis	= 13,
47
	Awaninfo	= 14,
48
	Alinkinfo	= 15,
49
};
50
 
51
 
52
struct Event {
53
	QLock;
54
	QLock waitlk;
55
	int	wait;
56
	int ready;
57
};
58
 
59
struct Call {
60
	int	ref;
61
	QLock	lk;
62
	int	id;
63
	int	serial;
64
	int	pppfd;
65
 
66
	int	closed;
67
 
68
	int	pac;	/* server is acting as a PAC */
69
 
70
	int	recvwindow;	/* recv windows */
71
	int	sendwindow;	/* send windows */
72
	int	delay;
73
 
74
	int	sendaccm;
75
	int	recvaccm;
76
 
77
	uint	seq;		/* current seq number - for send */
78
	uint	ack;		/* current acked mesg - for send */
79
	uint	rseq;		/* highest recv seq number for in order packet  */
80
	uint	rack;		/* highest ack sent */
81
 
82
	Event	eack;		/* recved ack - for send */
83
	ulong	tick;
84
 
85
	uchar	remoteip[IPaddrlen];	/* remote ip address */
86
	int	dhcpfd[2];	/* pipe to dhcpclient */
87
 
88
	/* error stats */
89
	struct {
90
		int	crc;
91
		int	frame;
92
		int	hardware;
93
		int	overrun;
94
		int	timeout;
95
		int	align;
96
	} err;
97
 
98
	struct {
99
		int	send;
100
		int	sendack;
101
		int	recv;
102
		int	recvack;
103
		int	dropped;
104
		int	missing;
105
		int	sendwait;
106
		int	sendtimeout;
107
	} stat;
108
 
109
	Call	*next;
110
};
111
 
112
struct {
113
	QLock	lk;
114
	int	start;
115
	int	grefd;
116
	int	grecfd;
117
	uchar	local[IPaddrlen];
118
	uchar	remote[IPaddrlen];
119
	char	*tcpdir;
120
	uchar	ipaddr[IPaddrlen];		/* starting ip addresss to allocate */
121
 
122
	int	recvwindow;
123
 
124
	char	*pppdir;
125
	char	*pppexec;
126
 
127
	double	rcvtime;	/* time at which last request was received */
128
	int	echoid;		/* id of last echo request */
129
 
130
	Call	*hash[Nhash];
131
} srv;
132
 
133
/* GRE flag bits */
134
enum {
135
	GRE_chksum	= (1<<15),
136
	GRE_routing	= (1<<14),
137
	GRE_key		= (1<<13),
138
	GRE_seq		= (1<<12),
139
	GRE_srcrt	= (1<<11),
140
	GRE_recur	= (7<<8),
141
	GRE_ack		= (1<<7),
142
	GRE_ver		= 0x7,
143
};
144
 
145
/* GRE protocols */
146
enum {
147
	GRE_ppp		= 0x880b,
148
};
149
 
150
int	debug;
151
double	drop;
152
 
153
void	myfatal(char *fmt, ...);
154
 
155
#define	PSHORT(p, v)		((p)[0]=((v)>>8), (p)[1]=(v))
156
#define	PLONG(p, v)		(PSHORT(p, (v)>>16), PSHORT(p+2, (v)))
157
#define	PSTRING(d,s,n)		strncpy((char*)(d), s, n)
158
#define	GSHORT(p)		(((p)[0]<<8) | ((p)[1]<<0))
159
#define	GLONG(p)		((GSHORT((p))<<16) | ((GSHORT((p)+2))<<0))
160
#define	GSTRING(d,s,n)		strncpy(d, (char*)(s), n), d[(n)-1] = 0
161
 
162
void	serve(void);
163
 
164
int	sstart(uchar*, int);
165
int	sstop(uchar*, int);
166
int	secho(uchar*, int);
167
int	scallout(uchar*, int);
168
int	scallreq(uchar*, int);
169
int	scallcon(uchar*, int);
170
int	scallclear(uchar*, int);
171
int	scalldis(uchar*, int);
172
int	swaninfo(uchar*, int);
173
int	slinkinfo(uchar*, int);
174
 
175
Call	*callalloc(int id);
176
void	callclose(Call*);
177
void	callfree(Call*);
178
Call	*calllookup(int id);
179
 
180
void	gretimeout(void*);
181
void	pppread(void*);
182
 
183
void	srvinit(void);
184
void	greinit(void);
185
void	greread(void*);
186
void	greack(Call *c);
187
 
188
void	timeoutthread(void*);
189
 
190
int	argatoi(char *p);
191
void	usage(void);
192
int	ipaddralloc(Call *c);
193
 
194
void	*emallocz(int size);
195
void	esignal(Event *e);
196
void	ewait(Event *e);
197
int	proc(char **argv, int fd0, int fd1, int fd2);
198
double	realtime(void);
199
ulong	thread(void(*f)(void*), void *a);
200
 
201
void
202
main(int argc, char *argv[])
203
{
204
	ARGBEGIN{
205
	case 'd': debug++; break;
206
	case 'p': srv.pppdir = ARGF(); break;
207
	case 'P': srv.pppexec = ARGF(); break;
208
	case 'w': srv.recvwindow = argatoi(ARGF()); break;
209
	case 'D': drop = atof(ARGF()); break;
210
	default:
211
		usage();
212
	}ARGEND
213
 
214
	fmtinstall('I', eipfmt);
215
	fmtinstall('E', eipfmt);
216
	fmtinstall('V', eipfmt);
217
	fmtinstall('M', eipfmt);
218
 
219
	rfork(RFNOTEG|RFREND);
220
 
221
	if(argc != 1)
222
		usage();
223
 
224
	srv.tcpdir = argv[0];
225
 
226
	srvinit();
227
 
228
	syslog(0, LOG, ": src=%I: pptp started: %d", srv.remote, getpid());
229
 
230
	SDB  "\n\n\n%I: pptp started\n", srv.remote EDB
231
 
232
	greinit();
233
 
234
	thread(timeoutthread, 0);
235
 
236
	serve();
237
 
238
	syslog(0, LOG, ": src=%I: server exits", srv.remote);
239
 
240
	exits(0);
241
}
242
 
243
void
244
usage(void)
245
{
246
	fprint(2, "usage: pptpd [-dD] [-p ppp-net] [-w window] tcpdir\n");
247
	exits("usage");
248
}
249
 
250
void
251
serve(void)
252
{
253
	uchar buf[2000], *p;
254
	int n, n2, len;
255
	int magic;
256
	int op, type;
257
 
258
	n = 0;
259
	for(;;) {
260
		n2 = read(0, buf+n, sizeof(buf)-n);
261
		if(n2 < 0)
262
			myfatal("bad read on ctl channel: %r");
263
		if(n2 == 0)
264
			break;
265
		n += n2;
266
		p = buf;
267
		for(;;) {
268
			if(n < 12)
269
				break;
270
 
271
			qlock(&srv.lk);
272
			srv.rcvtime = realtime();
273
			qunlock(&srv.lk);
274
 
275
			len = GSHORT(p);
276
			type = GSHORT(p+2);
277
			magic = GLONG(p+4);
278
			op = GSHORT(p+8);
279
			if(magic != Magic)
280
				myfatal("bad magic number: got %x", magic);
281
			if(type != 1)
282
				myfatal("bad message type: %d", type);
283
			switch(op) {
284
			default:
285
				myfatal("unknown control op: %d", op);
286
			case Tstart:		/* start-control-connection-request */
287
				n2 = sstart(p, n);
288
				break;
289
			case Tstop:
290
				n2 = sstop(p, n);
291
				if(n2 > 0)
292
					return;
293
				break;
294
			case Techo:
295
				n2 = secho(p, n);
296
				break;
297
			case Tcallout:
298
				n2 = scallout(p, n);
299
				break;
300
			case Tcallreq:
301
				n2 = scallreq(p, n);
302
				break;
303
			case Acallcon:
304
				n2 = scallcon(p, n);
305
				break;
306
			case Tcallclear:
307
				n2 = scallclear(p, n);
308
				break;
309
			case Acalldis:
310
				n2 = scalldis(p, n);
311
				break;
312
			case Awaninfo:
313
				n2 = swaninfo(p, n);
314
				break;
315
			case Alinkinfo:
316
				n2 = slinkinfo(p, n);
317
				break;
318
			}	
319
			if(n2 == 0)
320
				break;
321
			if(n2 != len)
322
				myfatal("op=%d: bad length: got %d expected %d", op, len, n2);
323
			n -= n2;
324
			p += n2;
325
 
326
		}
327
 
328
		/* move down partial message */
329
		if(p != buf && n != 0)
330
			memmove(buf, p, n);
331
	}
332
 
333
}
334
 
335
int
336
sstart(uchar *p, int n)
337
{
338
	int ver, frame, bearer, maxchan, firm;
339
	char host[64], vendor[64], *sysname;
340
	uchar buf[156];
341
 
342
	if(n < 156)
343
		return 0;
344
	ver = GSHORT(p+12);
345
	frame = GLONG(p+16);
346
	bearer = GLONG(p+20);
347
	maxchan = GSHORT(p+24);
348
	firm = GSHORT(p+26);
349
	GSTRING(host, p+28, 64);
350
	GSTRING(vendor, p+92, 64);
351
 
352
	SDB "%I: start ver = %x f = %d b = %d maxchan = %d firm = %d host = %s vendor = %s\n",
353
		srv.remote, ver, frame, bearer, maxchan, firm, host, vendor EDB
354
 
355
	if(ver != Version)
356
		myfatal("bad version: got %x expected %x", ver, Version);
357
 
358
	if(srv.start)
359
		myfatal("multiple start messages");
360
 
361
	srv.start = 1;
362
 
363
	sysname = getenv("sysname");
364
	if(sysname == 0)
365
		strcpy(host, "gnot");
366
	else
367
		strncpy(host, sysname, 64);
368
	free(sysname);
369
 
370
	memset(buf, 0, sizeof(buf));
371
 
372
	PSHORT(buf+0, sizeof(buf));	/* length */
373
	PSHORT(buf+2, 1);		/* message type */
374
	PLONG(buf+4, Magic);		/* magic */
375
	PSHORT(buf+8, Rstart);		/* op */
376
	PSHORT(buf+12, Version);	/* version */
377
	buf[14] = 1;			/* result = ok */
378
	PLONG(buf+16, Syncframe|Asyncframe);	/* frameing */
379
	PLONG(buf+20, Digital|Analog);	/* berear capabilities */
380
	PSHORT(buf+24, Nchan);		/* max channels */
381
	PSHORT(buf+26, 1);		/* driver version */
382
	PSTRING(buf+28, host, 64);	/* host name */
383
	PSTRING(buf+92, "plan 9", 64);	/* vendor */
384
 
385
	if(write(1, buf, sizeof(buf)) < sizeof(buf))
386
		myfatal("write failed: %r");
387
 
388
	return 156;
389
}
390
 
391
int
392
sstop(uchar *p, int n)
393
{
394
	int reason;
395
	uchar buf[16];
396
 
397
	if(n < 16)
398
		return 0;
399
	reason = p[12];
400
 
401
	SDB "%I: stop %d\n", srv.remote, reason EDB
402
 
403
	memset(buf, 0, sizeof(buf));
404
	PSHORT(buf+0, sizeof(buf));	/* length */
405
	PSHORT(buf+2, 1);		/* message type */
406
	PLONG(buf+4, Magic);		/* magic */
407
	PSHORT(buf+8, Rstop);		/* op */
408
	buf[12] = 1;			/* ok */
409
 
410
	if(write(1, buf, sizeof(buf)) < sizeof(buf))
411
		myfatal("write failed: %r");
412
 
413
	return 16;
414
}
415
 
416
int
417
secho(uchar *p, int n)
418
{
419
	int id;
420
	uchar buf[20];
421
 
422
	if(n < 16)
423
		return 0;
424
	id = GLONG(p+12);
425
 
426
	SDB "%I: echo %d\n", srv.remote, id EDB
427
 
428
	memset(buf, 0, sizeof(buf));
429
	PSHORT(buf+0, sizeof(buf));	/* length */
430
	PSHORT(buf+2, 1);		/* message type */
431
	PLONG(buf+4, Magic);		/* magic */
432
	PSHORT(buf+8, Recho);		/* op */
433
	PLONG(buf+12, id);		/* id */
434
	p[16] = 1;			/* ok */
435
 
436
	if(write(1, buf, sizeof(buf)) < sizeof(buf))
437
		myfatal("write failed: %r");
438
 
439
	return 16;
440
}
441
 
442
int
443
scallout(uchar *p, int n)
444
{
445
	int id, serial;
446
	int minbps, maxbps, bearer, frame;
447
	int window, delay;
448
	int nphone;
449
	char phone[64], sub[64], buf[32];
450
	Call *c;
451
 
452
	if(n < 168)
453
		return 0;
454
 
455
	if(!srv.start)
456
		myfatal("%I: did not recieve start message", srv.remote);
457
 
458
	id = GSHORT(p+12);
459
	serial = GSHORT(p+14);
460
	minbps = GLONG(p+16);
461
	maxbps = GLONG(p+20);
462
	bearer = GLONG(p+24);
463
	frame = GLONG(p+28);
464
	window = GSHORT(p+32);
465
	delay = GSHORT(p+34);
466
	nphone = GSHORT(p+36);
467
	GSTRING(phone, p+40, 64);
468
	GSTRING(sub, p+104, 64);
469
 
470
	SDB "%I: callout id = %d serial = %d bps=[%d,%d] b=%x f=%x win = %d delay = %d np=%d phone=%s sub=%s\n",
471
		srv.remote, id, serial, minbps, maxbps, bearer, frame, window, delay, nphone, phone, sub EDB
472
 
473
	c = callalloc(id);
474
	c->sendwindow = window;
475
	c->delay = delay;
476
	c->pac = 1;
477
	c->recvwindow = srv.recvwindow;
478
 
479
	memset(buf, 0, sizeof(buf));
480
	PSHORT(buf+0, sizeof(buf));	/* length */
481
	PSHORT(buf+2, 1);		/* message type */
482
	PLONG(buf+4, Magic);		/* magic */
483
	PSHORT(buf+8, Rcallout);	/* op */
484
	PSHORT(buf+12, id);		/* call id */
485
	PSHORT(buf+14, id);		/* peer id */
486
	buf[16] = 1;			/* ok */
487
	PLONG(buf+20, 10000000);	/* speed */
488
	PSHORT(buf+24, c->recvwindow);	/* window size */
489
	PSHORT(buf+26, 0);		/* delay */
490
	PLONG(buf+28, 0);		/* channel id */
491
 
492
	if(write(1, buf, sizeof(buf)) < sizeof(buf))
493
		myfatal("write failed: %r");
494
 
495
	return 168;
496
}
497
 
498
int
499
scallreq(uchar *p, int n)
500
{
501
	USED(p);
502
	USED(n);
503
 
504
	myfatal("callreq: not done yet");
505
	return 0;
506
}
507
 
508
int
509
scallcon(uchar *p, int n)
510
{
511
	USED(p);
512
	USED(n);
513
 
514
	myfatal("callcon: not done yet");
515
	return 0;
516
}
517
 
518
int
519
scallclear(uchar *p, int n)
520
{
521
	Call *c;
522
	int id;
523
	uchar buf[148];
524
 
525
	if(n < 16)
526
		return 0;
527
	id = GSHORT(p+12);
528
 
529
	SDB "%I: callclear id=%d\n", srv.remote, id EDB
530
 
531
	if(c = calllookup(id)) {
532
		callclose(c);
533
		callfree(c);
534
	}
535
 
536
	memset(buf, 0, sizeof(buf));
537
	PSHORT(buf+0, sizeof(buf));	/* length */
538
	PSHORT(buf+2, 1);		/* message type */
539
	PLONG(buf+4, Magic);		/* magic */
540
	PSHORT(buf+8, Acalldis);	/* op */
541
	PSHORT(buf+12, id);		/* id */
542
	buf[14] = 3;			/* reply to callclear */
543
 
544
	if(write(1, buf, sizeof(buf)) < sizeof(buf))
545
		myfatal("write failed: %r");
546
 
547
	return 16;
548
}
549
 
550
int
551
scalldis(uchar *p, int n)
552
{
553
	Call *c;
554
	int id, res;
555
 
556
	if(n < 148)
557
		return 0;
558
	id = GSHORT(p+12);
559
	res = p[14];
560
 
561
	SDB "%I: calldis id=%d res=%d\n", srv.remote, id, res EDB
562
 
563
	if(c = calllookup(id)) {
564
		callclose(c);
565
		callfree(c);
566
	}
567
 
568
	return 148;
569
}
570
 
571
int
572
swaninfo(uchar *p, int n)
573
{
574
	Call *c;
575
	int id;
576
 
577
	if(n < 40)
578
		return 0;
579
 
580
	id = GSHORT(p+12);
581
	SDB "%I: waninfo id = %d\n", srv.remote, id EDB
582
 
583
	c = calllookup(id);
584
	if(c != 0) {
585
		c->err.crc = GLONG(p+16);
586
		c->err.frame = GLONG(p+20);
587
		c->err.hardware = GLONG(p+24);
588
		c->err.overrun = GLONG(p+28);
589
		c->err.timeout = GLONG(p+32);
590
		c->err.align = GLONG(p+36);
591
 
592
		callfree(c);
593
	}
594
 
595
 
596
	return 40;
597
}
598
 
599
int
600
slinkinfo(uchar *p, int n)
601
{
602
	Call *c;
603
	int id;
604
	int sendaccm, recvaccm;
605
 
606
	if(n < 24)
607
		return 0;
608
	id = GSHORT(p+12);
609
	sendaccm = GLONG(p+16);
610
	recvaccm = GLONG(p+20);
611
 
612
	SDB "%I: linkinfo id=%d saccm=%ux raccm=%ux\n", srv.remote, id, sendaccm, recvaccm EDB
613
 
614
	if(c = calllookup(id)) {
615
		c->sendaccm = sendaccm;
616
		c->recvaccm = recvaccm;
617
 
618
		callfree(c);
619
	}
620
 
621
	return 24;
622
}
623
 
624
Call*
625
callalloc(int id)
626
{
627
	uint h;
628
	Call *c;
629
	char buf[300], *argv[30], local[20], remote[20], **p;
630
	int fd, pfd[2], n;
631
 
632
	h = id%Nhash;
633
 
634
	qlock(&srv.lk);
635
	for(c=srv.hash[h]; c; c=c->next)
636
		if(c->id == id)
637
			myfatal("callalloc: duplicate id: %d", id);
638
	c = emallocz(sizeof(Call));
639
	c->ref = 1;
640
	c->id = id;
641
	c->sendaccm = ~0;
642
	c->recvaccm = ~0;
643
 
644
	if(!ipaddralloc(c))
645
		myfatal("callalloc: could not alloc remote ip address");
646
 
647
	if(pipe(pfd) < 0)
648
		myfatal("callalloc: pipe failed: %r");
649
 
650
	sprint(buf, "%s/ipifc/clone", srv.pppdir);
651
	fd = open(buf, OWRITE);
652
	if(fd < 0)
653
		myfatal("callalloc: could not open %s: %r", buf);
654
 
655
	n = sprint(buf, "iprouting");
656
	if(write(fd, buf, n) < n)
657
		myfatal("callalloc: write to ifc failed: %r");
658
	close(fd);
659
 
660
	p = argv;
661
	*p++ = srv.pppexec;
662
	*p++ = "-SC";
663
	*p++ = "-x";
664
	*p++ = srv.pppdir;
665
	if(debug)
666
		*p++ = "-d";
667
	sprint(local, "%I", srv.ipaddr);
668
	*p++ = local;
669
	sprint(remote, "%I", c->remoteip);
670
	*p++ = remote;
671
	*p = 0;
672
 
673
	proc(argv, pfd[0], pfd[0], 2);
674
 
675
	close(pfd[0]);
676
 
677
	c->pppfd = pfd[1];
678
 
679
	c->next = srv.hash[h];
680
	srv.hash[h] = c;
681
 
682
	qunlock(&srv.lk);
683
 
684
	c->ref++;
685
	thread(pppread, c);
686
	c->ref++;
687
	thread(gretimeout, c);
688
 
689
	syslog(0, LOG, ": src=%I: call started: id=%d: remote ip=%I", srv.remote, id, c->remoteip);
690
 
691
	return c;
692
}
693
 
694
void
695
callclose(Call *c)
696
{
697
	Call *oc;
698
	int id;
699
	uint h;
700
 
701
	syslog(0, LOG, ": src=%I: call closed: id=%d: send=%d sendack=%d recv=%d recvack=%d dropped=%d missing=%d sendwait=%d sendtimeout=%d",
702
		srv.remote, c->id, c->stat.send, c->stat.sendack, c->stat.recv, c->stat.recvack,
703
		c->stat.dropped, c->stat.missing, c->stat.sendwait, c->stat.sendtimeout);
704
 
705
	qlock(&srv.lk);
706
	if(c->closed) {
707
		qunlock(&srv.lk);
708
		return;
709
	}
710
	c->closed = 1;
711
 
712
	close(c->dhcpfd[0]);
713
	close(c->dhcpfd[1]);
714
	close(c->pppfd);
715
	c->pppfd = -1;
716
 
717
	h = c->id%Nhash;
718
	id = c->id;
719
	for(c=srv.hash[h],oc=0; c; oc=c,c=c->next)
720
		if(c->id == id)
721
			break;
722
	if(oc == 0)
723
		srv.hash[h] = c->next;
724
	else
725
		oc->next = c->next;
726
	c->next = 0;
727
	qunlock(&srv.lk);
728
 
729
	callfree(c);
730
}
731
 
732
void
733
callfree(Call *c)
734
{	
735
	int ref;
736
 
737
	qlock(&srv.lk);
738
	ref = --c->ref;
739
	qunlock(&srv.lk);
740
	if(ref > 0)
741
		return;
742
 
743
	/* already unhooked from hash list - see callclose */
744
	assert(c->closed == 1);
745
	assert(ref == 0);
746
	assert(c->next == 0);
747
 
748
SDB "call free\n" EDB	
749
	free(c);
750
}
751
 
752
Call*
753
calllookup(int id)
754
{
755
	uint h;
756
	Call *c;
757
 
758
	h = id%Nhash;
759
 
760
	qlock(&srv.lk);
761
	for(c=srv.hash[h]; c; c=c->next)
762
		if(c->id == id)
763
			break;
764
	if(c != 0)
765
		c->ref++;
766
	qunlock(&srv.lk);
767
 
768
	return c;
769
}
770
 
771
 
772
void
773
srvinit(void)
774
{
775
	char buf[100];
776
	int fd, n;
777
 
778
	sprint(buf, "%s/local", srv.tcpdir);
779
	if((fd = open(buf, OREAD)) < 0)
780
		myfatal("could not open %s: %r", buf);
781
	if((n = read(fd, buf, sizeof(buf))) < 0)
782
		myfatal("could not read %s: %r", buf);
783
	buf[n] = 0;
784
	parseip(srv.local, buf);
785
	close(fd);
786
 
787
	sprint(buf, "%s/remote", srv.tcpdir);
788
	if((fd = open(buf, OREAD)) < 0)
789
		myfatal("could not open %s: %r", buf);
790
	if((n = read(fd, buf, sizeof(buf))) < 0)
791
		myfatal("could not read %s: %r", buf);
792
	buf[n] = 0;
793
	parseip(srv.remote, buf);
794
	close(fd);
795
 
796
	if(srv.pppdir == 0)
797
		srv.pppdir = "/net";
798
 
799
	if(srv.pppexec == 0)
800
		srv.pppexec = "/bin/ip/ppp";
801
 
802
	if(myipaddr(srv.ipaddr, srv.pppdir) < 0)
803
		myfatal("could not read local ip addr: %r");
804
	if(srv.recvwindow == 0)
805
		srv.recvwindow = Window;
806
}
807
 
808
void
809
greinit(void)
810
{
811
	char addr[100], *p;
812
	int fd, cfd;
813
 
814
	SDB "srv.tcpdir = %s\n", srv.tcpdir EDB
815
	strcpy(addr, srv.tcpdir);
816
	p = strrchr(addr, '/');
817
	if(p == 0)
818
		myfatal("bad tcp dir: %s", srv.tcpdir);
819
	*p = 0;
820
	p = strrchr(addr, '/');
821
	if(p == 0)
822
		myfatal("bad tcp dir: %s", srv.tcpdir);
823
	sprint(p, "/gre!%I!34827", srv.remote);
824
 
825
	SDB "addr = %s\n", addr EDB
826
 
827
	fd = dial(addr, 0, 0, &cfd);
828
 
829
	if(fd < 0)
830
		myfatal("%I: dial %s failed: %r", srv.remote, addr);
831
 
832
	srv.grefd = fd;
833
	srv.grecfd = cfd;
834
 
835
	thread(greread, 0);
836
}
837
 
838
void
839
greread(void *)
840
{
841
	uchar buf[Pktsize], *p;
842
	int n, i;
843
	int flag, prot, len, callid;
844
	uchar src[IPaddrlen], dst[IPaddrlen];
845
	uint rseq, ack;
846
	Call *c;
847
	static double t, last;
848
 
849
	for(;;) {
850
		n = read(srv.grefd, buf, sizeof(buf));
851
		if(n < 0)
852
			myfatal("%I: bad read on gre: %r", srv.remote);
853
		if(n == sizeof(buf))
854
			myfatal("%I: gre read: buf too small", srv.remote);
855
 
856
		p = buf;
857
		v4tov6(src, p);
858
		v4tov6(dst, p+4);
859
		flag = GSHORT(p+8);
860
		prot = GSHORT(p+10);
861
		p += 12; n -= 12;
862
 
863
		if(ipcmp(src, srv.remote) != 0 || ipcmp(dst, srv.local) != 0)
864
			myfatal("%I: gre read bad address src=%I dst=%I", srv.remote, src, dst);
865
 
866
		if(prot != GRE_ppp)
867
			myfatal("%I: gre read gave bad protocol", srv.remote);
868
 
869
		if(flag & (GRE_chksum|GRE_routing)){
870
			p += 4; n -= 4;
871
		}
872
 
873
		if(!(flag&GRE_key))
874
			myfatal("%I: gre packet does not contain a key: f=%ux",
875
				srv.remote, flag);
876
 
877
		len = GSHORT(p);
878
		callid = GSHORT(p+2);
879
		p += 4; n -= 4;
880
 
881
		c = calllookup(callid);
882
		if(c == 0) {
883
			SDB "%I: unknown callid: %d\n", srv.remote, callid EDB
884
			continue;
885
		}
886
 
887
		qlock(&c->lk);
888
 
889
		c->stat.recv++;
890
 
891
		if(flag&GRE_seq) {
892
			rseq = GLONG(p);
893
			p += 4; n -= 4;
894
		} else
895
			rseq = c->rseq;
896
 
897
		if(flag&GRE_ack){
898
			ack = GLONG(p);
899
			p += 4; n -= 4;
900
		} else
901
			ack = c->ack;
902
 
903
		/* skip routing if present */
904
		if(flag&GRE_routing) {
905
			while((i=p[3]) != 0) {
906
				n -= i;
907
				p += i;
908
			}
909
		}
910
 
911
		if(len > n)
912
			myfatal("%I: bad len in gre packet", srv.remote);
913
 
914
		if((int)(ack-c->ack) > 0) {
915
			c->ack = ack;
916
			esignal(&c->eack);
917
		}
918
 
919
		if(debug)
920
			t = realtime();
921
 
922
		if(len == 0) {
923
			/* ack packet */
924
			c->stat.recvack++;
925
 
926
SDB "%I: %.3f (%.3f): gre %d: recv ack a=%ux n=%d flag=%ux\n", srv.remote, t, t-last,
927
	c->id, ack, n, flag EDB
928
 
929
		} else {
930
 
931
SDB "%I: %.3f (%.3f): gre %d: recv s=%ux a=%ux len=%d\n", srv.remote, t, t-last,
932
	c->id, rseq, ack, len EDB
933
 
934
			/*
935
			 * the following handles the case of a single pair of packets
936
			 * received out of order
937
			 */
938
			n = rseq-c->rseq;
939
			if(n > 0 && (drop == 0. || frand() > drop)) {
940
				c->stat.missing += n-1;
941
				/* current packet */
942
				write(c->pppfd, p, len);
943
			} else {
944
				/* out of sequence - drop on the floor */
945
				c->stat.dropped++;
946
 
947
SDB "%I: %.3f: gre %d: recv out of order or dup packet: seq=%ux len=%d\n",
948
srv.remote, realtime(), c->id, rseq, len EDB
949
 
950
			}
951
		}
952
 
953
		if((int)(rseq-c->rseq) > 0)
954
			c->rseq = rseq;
955
 
956
		if(debug)
957
			last=t;
958
 
959
		/* open up client window */
960
		if((int)(c->rseq-c->rack) > (c->recvwindow>>1))
961
			greack(c);
962
 
963
		qunlock(&c->lk);
964
 
965
 
966
		callfree(c);
967
	}
968
}
969
 
970
void
971
greack(Call *c)
972
{
973
	uchar buf[20];
974
 
975
	c->stat.sendack++;
976
 
977
SDB "%I: %.3f: gre %d: send ack %ux\n", srv.remote, realtime(), c->id, c->rseq EDB
978
 
979
	v6tov4(buf+0, srv.local);		/* source */
980
	v6tov4(buf+4, srv.remote);		/* source */
981
	PSHORT(buf+8, GRE_key|GRE_ack|1);
982
	PSHORT(buf+10, GRE_ppp);
983
	PSHORT(buf+12, 0);
984
	PSHORT(buf+14, c->id);
985
	PLONG(buf+16, c->rseq);
986
 
987
	write(srv.grefd, buf, sizeof(buf));
988
 
989
	c->rack = c->rseq;
990
 
991
}
992
 
993
void
994
gretimeout(void *a)
995
{
996
	Call *c;
997
 
998
	c = a;
999
 
1000
	while(!c->closed) {
1001
		sleep(Tick);
1002
		qlock(&c->lk);
1003
		c->tick++;
1004
		qunlock(&c->lk);
1005
		esignal(&c->eack);
1006
	}
1007
	callfree(c);
1008
	exits(0);
1009
}
1010
 
1011
 
1012
void
1013
pppread(void *a)
1014
{
1015
	Call *c;
1016
	uchar buf[2000], *p;
1017
	int n;
1018
	ulong tick;
1019
 
1020
	c = a;
1021
	for(;;) {
1022
		p = buf+24;
1023
		n = read(c->pppfd, p, sizeof(buf)-24);
1024
		if(n <= 0)
1025
			break;
1026
 
1027
		qlock(&c->lk);
1028
 
1029
		/* add gre header */
1030
		c->seq++;
1031
		tick = c->tick;
1032
 
1033
		while(c->seq-c->ack>c->sendwindow && c->tick-tick<Sendtimeout && !c->closed) {
1034
			c->stat.sendwait++;
1035
SDB "window full seq = %d ack = %ux window = %ux\n", c->seq, c->ack, c->sendwindow EDB
1036
			qunlock(&c->lk);
1037
			ewait(&c->eack);
1038
			qlock(&c->lk);
1039
		}
1040
 
1041
		if(c->tick-tick >= Sendtimeout) {
1042
			c->stat.sendtimeout++;
1043
SDB "send timeout = %d ack = %ux window = %ux\n", c->seq, c->ack, c->sendwindow EDB
1044
		}
1045
 
1046
		v6tov4(buf+0, srv.local);		/* source */
1047
		v6tov4(buf+4, srv.remote);		/* source */
1048
		PSHORT(buf+8, GRE_key|GRE_seq|GRE_ack|1);
1049
		PSHORT(buf+10, GRE_ppp);
1050
		PSHORT(buf+12, n);
1051
		PSHORT(buf+14, c->id);
1052
		PLONG(buf+16, c->seq);
1053
		PLONG(buf+20, c->rseq);
1054
 
1055
		c->stat.send++;
1056
		c->rack = c->rseq;
1057
 
1058
SDB "%I: %.3f: gre %d: send s=%ux a=%ux len=%d\n", srv.remote, realtime(),
1059
	c->id,  c->seq, c->rseq, n EDB
1060
 
1061
		if(drop == 0. || frand() > drop)
1062
			if(write(srv.grefd, buf, n+24)<n+24)
1063
				myfatal("pppread: write failed: %r");
1064
 
1065
		qunlock(&c->lk);
1066
	}
1067
 
1068
	SDB "pppread exit: %d\n", c->id);
1069
 
1070
	callfree(c);
1071
	exits(0);
1072
}
1073
 
1074
void
1075
timeoutthread(void*)
1076
{
1077
	for(;;) {
1078
		sleep(30*1000);
1079
 
1080
		qlock(&srv.lk);
1081
		if(realtime() - srv.rcvtime > 5*60)
1082
			myfatal("server timedout");
1083
		qunlock(&srv.lk);
1084
	}
1085
}
1086
 
1087
 
1088
/* use syslog() rather than fprint(2, ...) */
1089
void
1090
myfatal(char *fmt, ...)
1091
{
1092
	char sbuf[512];
1093
	va_list arg;
1094
	uchar buf[16];
1095
 
1096
	/* NT don't seem to like us just going away */
1097
	memset(buf, 0, sizeof(buf));
1098
	PSHORT(buf+0, sizeof(buf));	/* length */
1099
	PSHORT(buf+2, 1);		/* message type */
1100
	PLONG(buf+4, Magic);		/* magic */
1101
	PSHORT(buf+8, Tstop);		/* op */
1102
	buf[12] = 3;			/* local shutdown */
1103
 
1104
	write(1, buf, sizeof(buf));
1105
 
1106
	va_start(arg, fmt);
1107
	vseprint(sbuf, sbuf+sizeof(sbuf), fmt, arg);
1108
	va_end(arg);
1109
 
1110
	SDB "%I: fatal: %s\n", srv.remote, sbuf EDB
1111
	syslog(0, LOG, ": src=%I: fatal: %s", srv.remote, sbuf);
1112
 
1113
	close(0);
1114
	close(1);
1115
	close(srv.grefd);
1116
	close(srv.grecfd);
1117
 
1118
	postnote(PNGROUP, getpid(), "die");
1119
	exits(sbuf);
1120
}
1121
 
1122
int
1123
argatoi(char *p)
1124
{
1125
	char *q;
1126
	int i;
1127
 
1128
	if(p == 0)
1129
		usage();
1130
 
1131
	i = strtol(p, &q, 0);
1132
	if(q == p)
1133
		usage();
1134
	return i;
1135
}
1136
 
1137
void
1138
dhcpclientwatch(void *a)
1139
{
1140
	Call *c = a;
1141
	uchar buf[1];
1142
 
1143
	for(;;) {
1144
		if(read(c->dhcpfd[0], buf, sizeof(buf)) <= 0)
1145
			break;
1146
	}
1147
	if(!c->closed)
1148
		myfatal("dhcpclient terminated");
1149
	callfree(c);
1150
	exits(0);
1151
}
1152
 
1153
int
1154
ipaddralloc(Call *c)
1155
{
1156
	int pfd[2][2];
1157
	char *argv[4], *p;
1158
	Biobuf bio;
1159
 
1160
	argv[0] = "/bin/ip/dhcpclient";
1161
	argv[1] = "-x";
1162
	argv[2] = srv.pppdir;
1163
	argv[3] = 0;
1164
 
1165
	if(pipe(pfd[0])<0)
1166
		myfatal("ipaddralloc: pipe failed: %r");
1167
	if(pipe(pfd[1])<0)
1168
		myfatal("ipaddralloc: pipe failed: %r");
1169
 
1170
	if(proc(argv, pfd[0][0], pfd[1][1], 2) < 0)
1171
		myfatal("ipaddralloc: proc failed: %r");
1172
 
1173
	close(pfd[0][0]);
1174
	close(pfd[1][1]);
1175
	c->dhcpfd[0] = pfd[1][0];
1176
	c->dhcpfd[1] = pfd[0][1];
1177
 
1178
	Binit(&bio, pfd[1][0], OREAD);
1179
	for(;;) {
1180
		p = Brdline(&bio, '\n');
1181
		if(p == 0)
1182
			break;
1183
		if(strncmp(p, "ip=", 3) == 0) {
1184
			p += 3;
1185
			parseip(c->remoteip, p);
1186
		} else if(strncmp(p, "end\n", 4) == 0)
1187
			break;
1188
	}
1189
 
1190
	Bterm(&bio);
1191
 
1192
	c->ref++;
1193
 
1194
	thread(dhcpclientwatch, c);
1195
 
1196
	return ipcmp(c->remoteip, IPnoaddr) != 0;
1197
}
1198
 
1199
 
1200
void
1201
esignal(Event *e)
1202
{	
1203
	qlock(e);
1204
	if(e->wait == 0) {
1205
		e->ready = 1;
1206
		qunlock(e);
1207
		return;
1208
	}
1209
	assert(e->ready == 0);
1210
	e->wait = 0;
1211
	rendezvous(e, (void*)1);
1212
	qunlock(e);
1213
}
1214
 
1215
void
1216
ewait(Event *e)
1217
{
1218
	qlock(&e->waitlk);
1219
	qlock(e);
1220
	assert(e->wait == 0);
1221
	if(e->ready) {
1222
		e->ready = 0;
1223
	} else {	
1224
		e->wait = 1;
1225
		qunlock(e);
1226
		rendezvous(e, (void*)2);
1227
		qlock(e);
1228
	}
1229
	qunlock(e);
1230
	qunlock(&e->waitlk);
1231
}
1232
 
1233
ulong
1234
thread(void(*f)(void*), void *a)
1235
{
1236
	int pid;
1237
	pid=rfork(RFNOWAIT|RFMEM|RFPROC);
1238
	if(pid < 0)
1239
		myfatal("rfork failed: %r");
1240
	if(pid != 0)
1241
		return pid;
1242
	(*f)(a);
1243
	return 0; // never reaches here
1244
}
1245
 
1246
double
1247
realtime(void)
1248
{
1249
	long times(long*);
1250
 
1251
	return times(0) / 1000.0;
1252
}
1253
 
1254
void *
1255
emallocz(int size)
1256
{
1257
	void *p;
1258
	p = malloc(size);
1259
	if(p == 0)
1260
		myfatal("malloc failed: %r");
1261
	memset(p, 0, size);
1262
	return p;
1263
}
1264
 
1265
static void
1266
fdclose(void)
1267
{
1268
	int fd, n, i;
1269
	Dir *d, *p;
1270
 
1271
	if((fd = open("#d", OREAD)) < 0)
1272
		return;
1273
 
1274
	n = dirreadall(fd, &d);
1275
	for(p = d; n > 0; n--, p++) {
1276
		i = atoi(p->name);
1277
		if(i > 2)
1278
			close(i);
1279
	}
1280
	free(d);
1281
}
1282
 
1283
int
1284
proc(char **argv, int fd0, int fd1, int fd2)
1285
{
1286
	int r, flag;
1287
	char *arg0, file[200];
1288
 
1289
	arg0 = argv[0];
1290
 
1291
	strcpy(file, arg0);
1292
 
1293
	if(access(file, 1) < 0) {
1294
		if(strncmp(arg0, "/", 1)==0
1295
		|| strncmp(arg0, "#", 1)==0
1296
		|| strncmp(arg0, "./", 2)==0
1297
		|| strncmp(arg0, "../", 3)==0)
1298
			return 0;
1299
		sprint(file, "/bin/%s", arg0);
1300
		if(access(file, 1) < 0)
1301
			return 0;
1302
	}
1303
 
1304
	flag = RFPROC|RFFDG|RFENVG|RFNOWAIT;
1305
	if((r = rfork(flag)) != 0) {
1306
		if(r < 0)
1307
			return 0;
1308
		return r;
1309
	}
1310
 
1311
	if(fd0 != 0) {
1312
		if(fd1 == 0)
1313
			fd1 = dup(0, -1);
1314
		if(fd2 == 0)
1315
			fd2 = dup(0, -1);
1316
		close(0);
1317
		if(fd0 >= 0)
1318
			dup(fd0, 0);
1319
	}
1320
 
1321
	if(fd1 != 1) {
1322
		if(fd2 == 1)
1323
			fd2 = dup(1, -1);
1324
		close(1);
1325
		if(fd1 >= 0)
1326
			dup(fd1, 1);
1327
	}
1328
 
1329
	if(fd2 != 2) {
1330
		close(2);
1331
		if(fd2 >= 0)
1332
			dup(fd2, 2);
1333
	}
1334
 
1335
	fdclose();
1336
 
1337
	exec(file, argv);
1338
	myfatal("proc: exec failed: %r");
1339
	return 0;
1340
}
1341