Subversion Repositories planix.SVN

Rev

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

Rev Author Line No. Line
2 - 1
/*
2
 * Point-to-point Tunneling Protocol (PPTP)
3
 * See RFC 2637, pptpd.c
4
 */
5
 
6
#include <u.h>
7
#include <libc.h>
8
#include <bio.h>
9
#include <ip.h>
10
#include <thread.h>
11
 
12
int	ack;
13
int	alarmed;
14
int	ctlechotime;
15
int	ctlfd;
16
int	ctlrcvtime;
17
int	debug;
18
int	grefd;
19
uchar localip[IPaddrlen];
20
int	localwin;
21
char	*keyspec;
22
int	now;
23
char	*pppnetmntpt;
24
int	pid;
25
Channel *pidchan;
26
int	pppfd;
27
int	primary;
28
int	rack;
29
Channel	*rdchan;
30
int	rdexpect;
31
int	remid;
32
uchar remoteip[IPaddrlen];
33
int	remwin;
34
int	rseq;
35
int	seq;
36
char	tcpdir[40];
37
Channel *tickchan;
38
int	topppfd;
39
 
40
int	aread(int, int, void*, int);
41
int	catchalarm(void*, char*);
42
void	dumpctlpkt(uchar*);
43
void	getaddrs(void);
44
void	*emalloc(long);
45
void	ewrite(int, void*, int);
46
void	myfatal(char*, ...);
47
#pragma varargck argpos myfatal 1
48
int	pptp(char*);
49
void	pushppp(int);
50
void	recordack(int);
51
int	schedack(int, uchar*, int);
52
void	waitacks(void);
53
 
54
void
55
usage(void)
56
{
57
	fprint(2, "usage: ip/pptp [-Pd] [-k keyspec] [-x pppnetmntpt] [-w window] server\n");
58
	exits("usage");
59
}
60
 
61
void
62
threadmain(int argc, char **argv)
63
{
64
	int fd;
65
 
66
	ARGBEGIN{
67
	case 'P':
68
		primary = 1;
69
		break;
70
	case 'd':
71
		debug++;
72
		break;
73
	case 'k':
74
		keyspec = EARGF(usage());
75
		break;
76
	case 'w':
77
		localwin = atoi(EARGF(usage()));
78
		break;
79
	case 'x':
80
		pppnetmntpt = EARGF(usage());
81
		break;
82
	default:
83
		usage();
84
	}ARGEND
85
 
86
	if(argc != 1)
87
		usage();
88
 
89
	fmtinstall('E', eipfmt);
90
	fmtinstall('I', eipfmt);
91
 
92
	rfork(RFNOTEG);
93
	atnotify(catchalarm, 1);
94
	fd = pptp(argv[0]);
95
	pushppp(fd);
96
	exits(nil);
97
}
98
 
99
int
100
catchalarm(void *a, char *msg)
101
{
102
	USED(a);
103
 
104
	if(strstr(msg, "alarm")){
105
		alarmed = 1;
106
		return 1;
107
	}
108
	if(debug)
109
		fprint(2, "note rcved: %s\n", msg);
110
	return 0;
111
}
112
 
113
enum {
114
	Stack	= 8192,
115
 
116
	PptpProto	= 0x0100,
117
 
118
	Magic	= 0x1a2b3c4d,
119
	Window	= 16,		/* default window size */
120
	Timeout	= 60,		/* timeout in seconds for control channel */
121
	Pktsize = 2000,		/* maximum packet size */
122
	Tick	= 500,		/* tick length in milliseconds */
123
	Sendtimeout = 4,	/* in ticks */
124
 
125
	Servertimeout = 5*60*1000/Tick,
126
	Echointerval = 60*1000/Tick,
127
};
128
 
129
enum {
130
	Syncframe	= 0x1,
131
	Asyncframe	= 0x2,
132
	Analog		= 0x1,
133
	Digital		= 0x2,
134
	Version		= 0x100,
135
};
136
 
137
enum {
138
	Tstart		= 1,
139
	Rstart		= 2,
140
	Tstop		= 3,
141
	Rstop		= 4,
142
	Techo		= 5,
143
	Recho		= 6,
144
	Tcallout	= 7,
145
	Rcallout	= 8,
146
	Tcallreq	= 9,
147
	Rcallreq	= 10,
148
	Acallcon	= 11,
149
	Tcallclear	= 12,
150
	Acalldis	= 13,
151
	Awaninfo	= 14,
152
	Alinkinfo	= 15,
153
};
154
 
155
void
156
recho(uchar *in)
157
{
158
	uchar out[20];
159
 
160
	if(nhgets(in) < 16)
161
		return;
162
 
163
	memset(out, 0, sizeof out);
164
	hnputs(out, sizeof out);
165
	hnputs(out+2, 1);
166
	hnputl(out+4, Magic);
167
	hnputs(out+8, Recho);
168
	memmove(out+12, in+12, 4);
169
	out[16] = 1;
170
 
171
	ewrite(ctlfd, out, sizeof out);
172
}
173
 
174
void
175
sendecho(void)
176
{
177
	uchar out[16];
178
 
179
	ctlechotime = now;	
180
	memset(out, 0, sizeof out);
181
	hnputs(out, sizeof out);
182
	hnputs(out+2, 1);
183
	hnputl(out+4, Magic);
184
	hnputs(out+8, Techo);
185
 
186
	ewrite(ctlfd, out, sizeof out);
187
}
188
 
189
void
190
pptpctlproc(void*)
191
{
192
	uchar pkt[1600], *p;
193
	int len;
194
 
195
	for(;;){
196
		if(readn(ctlfd, pkt, 2) != 2)
197
			myfatal("pptpread: %r");
198
		len = nhgets(pkt);
199
		if(len < 12 || len+2 >= sizeof pkt)
200
			myfatal("pptpread: bad length %d", len);
201
		if(readn(ctlfd, pkt+2, len-2) != len-2)
202
			myfatal("pptpread: %r");
203
		if(nhgetl(pkt+4) != Magic)
204
			myfatal("pptpread bad magic");
205
		if(nhgets(pkt+2) != 1)
206
			myfatal("pptpread bad message type");
207
		if(debug)
208
			dumpctlpkt(pkt);
209
		ctlrcvtime = now;
210
 
211
		switch(nhgets(pkt+8)){
212
		case Tstart:
213
		case Tstop:
214
		case Tcallout:
215
		case Tcallreq:
216
		case Tcallclear:
217
		case Acallcon:
218
		case Acalldis:
219
		case Awaninfo:
220
			myfatal("unexpected msg type %d", nhgets(pkt+8));
221
		case Techo:
222
			recho(pkt);
223
			break;
224
		case Recho:
225
			break;
226
		case Rstart:
227
		case Rstop:
228
		case Rcallout:
229
		case Rcallreq:
230
			if(rdexpect != nhgets(pkt+8))
231
				continue;
232
			p = emalloc(len);
233
			memmove(p, pkt, len);
234
			sendp(rdchan, p);
235
			break;
236
		case Alinkinfo:
237
			myfatal("cannot change ppp params on the fly");
238
		}
239
	}
240
}
241
 
242
enum {
243
	Seqnum = 0x1000,
244
	Acknum = 0x0080,
245
 
246
	GrePPP = 0x880B,
247
};
248
 
249
void
250
grereadproc(void*)
251
{
252
	int datoff, flags, len, n, pass;
253
	uchar pkt[1600];
254
	uchar src[IPaddrlen], dst[IPaddrlen];
255
 
256
	rfork(RFFDG);
257
	close(pppfd);
258
	sendul(pidchan, getpid());
259
 
260
	while((n = read(grefd, pkt, sizeof pkt)) > 0){
261
		if(n == sizeof pkt)
262
			myfatal("gre pkt buffer too small");
263
		if(n < 16){
264
			if(debug)
265
				fprint(2, "small pkt len %d ignored\n", n);
266
			continue;
267
		}
268
		v4tov6(src, pkt);
269
		v4tov6(dst, pkt+4);
270
		if(ipcmp(src, remoteip) != 0 || ipcmp(dst, localip) != 0)
271
			myfatal("%I: gre read bad address src=%I dst=%I",
272
				remoteip, src, dst);
273
		if(nhgets(pkt+10) != GrePPP)
274
			myfatal("%I: gre read bad protocol 0x%x",
275
				remoteip, nhgets(pkt+10));
276
 
277
		flags = nhgets(pkt+8);
278
		if((flags&0xEF7F) != 0x2001){
279
			if(debug)
280
				fprint(2, "bad flags in gre hdr 0x%x\n", flags);
281
			continue;
282
		}
283
		datoff = 8+8;
284
		pass = 0;
285
		len = nhgets(pkt+8+4);
286
		if(len > n-datoff){
287
			fprint(2, "bad payload length %d > %d\n",
288
				len, n-datoff);
289
			continue;
290
		}
291
		if(flags&Seqnum)
292
			datoff += 4;
293
		if(flags&Acknum){
294
			recordack(nhgetl(pkt+datoff));
295
			datoff += 4;
296
		}
297
		if(flags&Seqnum)
298
			pass = schedack(nhgetl(pkt+8+8), pkt+datoff, len);
299
		if(debug)
300
			fprint(2, "got gre callid %d len %d flag 0x%x pass %d seq %d rseq %d\n", nhgets(pkt+8+6),
301
				len, flags, pass, nhgetl(pkt+8+8), rseq);
302
	}
303
	threadexits(nil);
304
}
305
 
306
void
307
pppreadproc(void*)
308
{
309
	int n, myrseq;
310
	uchar pkt[1600];
311
	enum {
312
		Hdr = 8+16,
313
	};
314
 
315
	rfork(RFFDG);
316
	close(pppfd);
317
	sendul(pidchan, getpid());
318
 
319
	while((n = read(topppfd, pkt+Hdr, sizeof pkt-Hdr)) > 0){
320
		if(n == sizeof pkt-Hdr)
321
			myfatal("ppp pkt buffer too small");
322
		v6tov4(pkt+0, localip);
323
		v6tov4(pkt+4, remoteip);
324
		hnputs(pkt+8, 0x2001 | Seqnum | Acknum);
325
		hnputs(pkt+10, GrePPP);
326
		hnputs(pkt+12, n);
327
		hnputs(pkt+14, remid);
328
		hnputl(pkt+16, ++seq);
329
		myrseq = rseq;
330
		hnputl(pkt+20, myrseq);
331
		rack = myrseq;
332
		if(debug)
333
			fprint(2, "wrote gre callid %d len %d flag 0x%x seq %d rseq %d\n", nhgets(pkt+8+6),
334
				n, nhgets(pkt+8), nhgetl(pkt+16), nhgetl(pkt+20));
335
		if(write(grefd, pkt, n+Hdr) != n+Hdr)
336
			myfatal("gre write: %r");
337
		waitacks();
338
	}
339
	threadexits(nil);
340
}
341
 
342
void
343
sendack(void)
344
{
345
	int myrseq;
346
	uchar pkt[20];
347
 
348
	v6tov4(pkt+0, localip);
349
	v6tov4(pkt+4, remoteip);
350
	hnputs(pkt+8, 0x2001 | Acknum);
351
	hnputs(pkt+10, GrePPP);
352
	hnputs(pkt+12, 0);
353
	hnputs(pkt+14, remid);
354
	myrseq = rseq;
355
	rack = myrseq;
356
	hnputs(pkt+16, myrseq);
357
 
358
	if(write(grefd, pkt, sizeof pkt) != sizeof pkt)
359
		myfatal("gre write: %r");
360
}
361
 
362
int
363
schedack(int n, uchar *dat, int len)
364
{
365
	static uchar sdat[1600];
366
	static int srseq, slen;
367
 
368
	if(n-rseq <= 0){
369
		fprint(2, "skipping pkt %d len %d, have %d\n", n, len, rseq);
370
		return 0;
371
	}
372
 
373
	/* missed one pkt, maybe a swap happened, save pkt */
374
	if(n==rseq+2){
375
		memmove(sdat, dat, len);
376
		slen = len;
377
		srseq = n;
378
		return 0;
379
	}
380
 
381
	if(n-rseq > 1){
382
		if(slen && srseq == n-1){	
383
			fprint(2, "reswapped pkts %d and %d\n", srseq, n);
384
			write(topppfd, sdat, slen);
385
			slen = 0;
386
		}else
387
			fprint(2, "missed pkts %d-%d, got %d len %d\n", rseq+1, n-1, n, len);
388
	}
389
	write(topppfd, dat, len);
390
	rseq = n;
391
 
392
	/* send ack if we haven't recently */
393
	if((int)(rseq-rack) > (localwin>>1))
394
		sendack();
395
 
396
	return 1;
397
}
398
 
399
void
400
gretimeoutproc(void*)
401
{
402
	for(;;){
403
		sleep(Tick);
404
		now++;
405
		nbsendul(tickchan, now);
406
		if(now - ctlrcvtime > Servertimeout)
407
			myfatal("server timeout");
408
		if(now - ctlechotime > Echointerval)
409
			sendecho();
410
	}
411
}
412
 
413
void
414
recordack(int n)
415
{
416
	ack = n;
417
}
418
 
419
void
420
waitacks(void)
421
{
422
/*
423
	int start;
424
 
425
	start = now;
426
	while(seq-ack > remwin && now-start < Sendtimeout){
427
		print("seq %d ack %d remwin %d now %d start %d\n",
428
			seq, ack, remwin, now, start);
429
		recvul(tickchan);
430
	}
431
*/
432
}
433
 
434
void
435
tstart(void)
436
{
437
	char *name;
438
	uchar pkt[200], *rpkt;
439
 
440
	memset(pkt, 0, sizeof pkt);
441
 
442
	hnputs(pkt+0, 156);
443
	hnputs(pkt+2, 1);
444
	hnputl(pkt+4, Magic);
445
	hnputs(pkt+8, Tstart);
446
	hnputs(pkt+12, PptpProto);
447
	hnputl(pkt+16, 1);
448
	hnputl(pkt+20, 1);
449
	hnputs(pkt+24, 1);
450
	name = sysname();
451
	if(name == nil)
452
		name = "gnot";
453
	strcpy((char*)pkt+28, name);
454
	strcpy((char*)pkt+92, "plan 9");
455
 
456
	if(debug)
457
		dumpctlpkt(pkt);
458
 
459
	rdexpect = Rstart;
460
	ewrite(ctlfd, pkt, 156);
461
 
462
	rpkt = recvp(rdchan);
463
	if(rpkt == nil)
464
		myfatal("recvp: %r");
465
	if(nhgets(rpkt) != 156)
466
		myfatal("Rstart wrong length %d != 156", nhgets(rpkt));
467
	if(rpkt[14] != 1)
468
		myfatal("Rstart error %d", rpkt[15]);
469
	free(rpkt);
470
}
471
 
472
void
473
tcallout(void)
474
{
475
	uchar pkt[200], *rpkt;
476
 
477
	pid = getpid();
478
 
479
	memset(pkt, 0, sizeof pkt);
480
	hnputs(pkt+0, 168);
481
	hnputs(pkt+2, 1);
482
	hnputl(pkt+4, Magic);
483
	hnputs(pkt+8, Tcallout);
484
 
485
	hnputl(pkt+16, 56000);
486
	hnputl(pkt+20, 768000);
487
	hnputl(pkt+24, 3);
488
	hnputl(pkt+28, 3);
489
	if(localwin == 0)
490
		localwin = Window;
491
	hnputs(pkt+32, localwin);
492
 
493
	if(debug)
494
		dumpctlpkt(pkt);
495
 
496
	rdexpect = Rcallout;
497
	ewrite(ctlfd, pkt, 168);
498
 
499
	rpkt = recvp(rdchan);
500
	if(rpkt == nil)
501
		myfatal("recvp: %r");
502
	if(nhgets(rpkt) != 32)
503
		myfatal("Rcallreq wrong length %d != 32", nhgets(rpkt));
504
	if(rpkt[16] != 1)
505
		myfatal("Rcallreq error %d", rpkt[17]);
506
	remid = nhgets(pkt+12);
507
	remwin = nhgets(pkt+24);
508
	free(rpkt);
509
}
510
 
511
/*
512
void
513
tcallreq(void)
514
{
515
	uchar pkt[200], *rpkt;
516
 
517
	pid = getpid();
518
 
519
	memset(pkt, 0, sizeof pkt);
520
	hnputs(pkt+0, 220);
521
	hnputs(pkt+2, 1);
522
	hnputl(pkt+4, Magic);
523
	hnputs(pkt+8, Tcallreq);
524
 
525
	if(debug)
526
		dumpctlpkt(pkt);
527
 
528
	rdexpect = Rcallreq;
529
	ewrite(ctlfd, pkt, 220);
530
 
531
	rpkt = recvp(rdchan);
532
	if(rpkt == nil)
533
		myfatal("recvp: %r");
534
	if(nhgets(rpkt) != 24)
535
		myfatal("Rcallreq wrong length %d != 24", nhgets(rpkt));
536
	if(rpkt[16] != 1)
537
		myfatal("Rcallreq error %d", rpkt[17]);
538
	remid = nhgets(pkt+12);
539
	remwin = nhgets(pkt+18);
540
	free(rpkt);
541
}
542
 
543
void
544
acallcon(void)
545
{
546
	uchar pkt[200];
547
 
548
	memset(pkt, 0, sizeof pkt);
549
	hnputs(pkt+0, 28);
550
	hnputs(pkt+2, 1);
551
	hnputl(pkt+4, Magic);
552
	hnputs(pkt+8, Acallcon);
553
	hnputs(pkt+12, remid);
554
	if(localwin == 0)
555
		localwin = Window;
556
	hnputs(pkt+20, localwin);
557
	hnputl(pkt+24, 1);
558
 
559
	if(debug)
560
		dumpctlpkt(pkt);
561
 
562
	ewrite(ctlfd, pkt, 28);
563
}
564
*/
565
 
566
int
567
pptp(char *addr)
568
{
569
	int p[2];
570
	char greaddr[128];
571
 
572
	addr = netmkaddr(addr, "net", "pptp");
573
	ctlfd = dial(addr, nil, tcpdir, nil);
574
	if(ctlfd < 0)
575
		myfatal("dial %s: %r", addr);
576
 	getaddrs();
577
 
578
	rdchan = chancreate(sizeof(void*), 0);
579
	proccreate(pptpctlproc, nil, Stack);
580
 
581
	tstart();
582
	tcallout();
583
 
584
	if(pipe(p) < 0)
585
		myfatal("pipe: %r");
586
 
587
	pppfd = p[0];
588
	topppfd = p[1];
589
 
590
	strcpy(greaddr, tcpdir);
591
	*strrchr(greaddr, '/') = '\0';
592
	sprint(strrchr(greaddr, '/')+1, "gre!%I!%d", remoteip, GrePPP);
593
 
594
	print("local %I remote %I gre %s remid %d remwin %d\n",
595
		localip, remoteip, greaddr, remid, remwin);
596
 
597
	grefd = dial(greaddr, nil, nil, nil);
598
	if(grefd < 0)
599
		myfatal("dial gre: %r");
600
 
601
	tickchan = chancreate(sizeof(int), 0);
602
	proccreate(gretimeoutproc, nil, Stack);
603
 
604
	pidchan = chancreate(sizeof(int), 0);
605
	proccreate(grereadproc, nil, Stack);
606
	recvul(pidchan);
607
	proccreate(pppreadproc, nil, Stack);
608
	recvul(pidchan);
609
 
610
	close(topppfd);
611
	return pppfd;
612
}
613
 
614
void
615
pushppp(int fd)
616
{
617
	char *argv[16];
618
	int argc;
619
 
620
	argc = 0;
621
	argv[argc++] = "/bin/ip/ppp";
622
	argv[argc++] = "-C";
623
	argv[argc++] = "-m1450";
624
	if(debug)
625
		argv[argc++] = "-d";
626
	if(primary)
627
		argv[argc++] = "-P";
628
	if(pppnetmntpt){
629
		argv[argc++] = "-x";
630
		argv[argc++] = pppnetmntpt;
631
	}
632
	if(keyspec){
633
		argv[argc++] = "-k";
634
		argv[argc++] = keyspec;
635
	}
636
	argv[argc] = nil;
637
 
638
	switch(fork()){
639
	case -1:
640
		myfatal("fork: %r");
641
	default:
642
		return;
643
	case 0:
644
		dup(fd, 0);
645
		dup(fd, 1);
646
		exec(argv[0], argv);
647
		myfatal("exec: %r");
648
	}
649
}
650
 
651
int
652
aread(int timeout, int fd, void *buf, int nbuf)
653
{
654
	int n;
655
 
656
	alarmed = 0;
657
	alarm(timeout);
658
	n = read(fd, buf, nbuf);
659
	alarm(0);
660
	if(alarmed)
661
		return -1;
662
	if(n < 0)
663
		myfatal("read: %r");
664
	if(n == 0)
665
		myfatal("short read");
666
	return n;
667
}
668
 
669
void
670
ewrite(int fd, void *buf, int nbuf)
671
{
672
	char e[ERRMAX], path[64];
673
 
674
	if(write(fd, buf, nbuf) != nbuf){
675
		rerrstr(e, sizeof e);
676
		strcpy(path, "unknown");
677
		fd2path(fd, path, sizeof path);
678
		myfatal("write %d to %s: %s", nbuf, path, e);
679
	}
680
}
681
 
682
void*
683
emalloc(long n)
684
{
685
	void *v;
686
 
687
	v = malloc(n);
688
	if(v == nil)
689
		myfatal("out of memory");
690
	return v;
691
}
692
 
693
int
694
thread(void(*f)(void*), void *a)
695
{
696
	int pid;
697
	pid=rfork(RFNOWAIT|RFMEM|RFPROC);
698
	if(pid < 0)
699
		myfatal("rfork: %r");
700
	if(pid != 0)
701
		return pid;
702
	(*f)(a);
703
	_exits(nil);
704
	return 0; // never reaches here
705
}
706
 
707
void
708
dumpctlpkt(uchar *pkt)
709
{
710
	fprint(2, "pkt len %d mtype %d cookie 0x%.8ux type %d\n",
711
		nhgets(pkt), nhgets(pkt+2),
712
		nhgetl(pkt+4), nhgets(pkt+8));
713
 
714
	switch(nhgets(pkt+8)){
715
	default:
716
		fprint(2, "\tunknown type\n");
717
		break;
718
	case Tstart:
719
		fprint(2, "\tTstart proto %d framing %d bearer %d maxchan %d firmware %d\n",
720
			nhgets(pkt+12), nhgetl(pkt+16),
721
			nhgetl(pkt+20), nhgets(pkt+24),
722
			nhgets(pkt+26));
723
		fprint(2, "\thost %.64s\n", (char*)pkt+28);
724
		fprint(2, "\tvendor %.64s\n", (char*)pkt+92);
725
		break;
726
	case Rstart:
727
		fprint(2, "\tRstart proto %d res %d err %d framing %d bearer %d maxchan %d firmware %d\n",
728
			nhgets(pkt+12), pkt[14], pkt[15],
729
			nhgetl(pkt+16),
730
			nhgetl(pkt+20), nhgets(pkt+24),
731
			nhgets(pkt+26));
732
		fprint(2, "\thost %.64s\n", (char*)pkt+28);
733
		fprint(2, "\tvendor %.64s\n", (char*)pkt+92);
734
		break;
735
 
736
	case Tstop:
737
		fprint(2, "\tTstop reason %d\n", pkt[12]);
738
		break;
739
 
740
	case Rstop:
741
		fprint(2, "\tRstop res %d err %d\n", pkt[12], pkt[13]);
742
		break;
743
 
744
	case Techo:
745
		fprint(2, "\tTecho id %.8ux\n", nhgetl(pkt+12));
746
		break;
747
 
748
	case Recho:
749
		fprint(2, "\tRecho id %.8ux res %d err %d\n", nhgetl(pkt+12), pkt[16], pkt[17]);
750
		break;
751
 
752
	case Tcallout:
753
		fprint(2, "\tTcallout id %d serno %d bps %d-%d\n",
754
			nhgets(pkt+12), nhgets(pkt+14),
755
			nhgetl(pkt+16), nhgetl(pkt+20));
756
		fprint(2, "\tbearer 0x%x framing 0x%x recvwin %d delay %d\n",
757
			nhgetl(pkt+24), nhgetl(pkt+28),
758
			nhgets(pkt+32), nhgets(pkt+34));
759
		fprint(2, "\tphone len %d num %.64s\n", 
760
			nhgets(pkt+36), (char*)pkt+40);
761
		fprint(2, "\tsubaddr %.64s\n", (char*)pkt+104);
762
		break;
763
 
764
	case Rcallout:
765
		fprint(2, "\tRcallout id %d peerid %d res %d err %d cause %d\n",
766
			nhgets(pkt+12), nhgets(pkt+14),
767
			pkt[16], pkt[17], nhgets(pkt+18));
768
		fprint(2, "\tconnect %d recvwin %d delay %d chan 0x%.8ux\n",
769
			nhgetl(pkt+20), nhgets(pkt+24),
770
			nhgets(pkt+26), nhgetl(pkt+28));
771
		break;
772
 
773
	case Tcallreq:
774
		fprint(2, "\tTcallreq id %d serno %d bearer 0x%x id 0x%x\n",
775
			nhgets(pkt+12), nhgets(pkt+14),
776
			nhgetl(pkt+16), nhgetl(pkt+20));
777
		fprint(2, "\tdialed len %d num %.64s\n",
778
			nhgets(pkt+24), (char*)pkt+28);
779
		fprint(2, "\tdialing len %d num %.64s\n",
780
			nhgets(pkt+26), (char*)pkt+92);
781
		fprint(2, "\tsubaddr %.64s\n", (char*)pkt+156);
782
		break;
783
 
784
	case Rcallreq:
785
		fprint(2, "\tRcallout id %d peerid %d res %d err %d recvwin %d delay %d\n",
786
			nhgets(pkt+12), nhgets(pkt+14),
787
			pkt[16], pkt[17], nhgets(pkt+18),
788
			nhgets(pkt+20));
789
		break;
790
 
791
	case Acallcon:
792
		fprint(2, "\tAcallcon peerid %d connect %d recvwin %d delay %d framing 0x%x\n",
793
			nhgets(pkt+12), nhgetl(pkt+16),
794
			nhgets(pkt+20), nhgets(pkt+22),
795
			nhgetl(pkt+24));
796
		break;
797
 
798
	case Tcallclear:
799
		fprint(2, "\tTcallclear callid %d\n",
800
			nhgets(pkt+12));
801
		break;
802
 
803
	case Acalldis:
804
		fprint(2, "\tAcalldis callid %d res %d err %d cause %d\n",
805
			nhgets(pkt+12), pkt[14], pkt[15],
806
			nhgets(pkt+16));
807
		fprint(2, "\tstats %.128s\n", (char*)pkt+20);
808
		break;
809
 
810
	case Awaninfo:
811
		fprint(2, "\tAwaninfo peerid %d\n", nhgets(pkt+12));
812
		fprint(2, "\tcrc errors %d\n", nhgetl(pkt+16));
813
		fprint(2, "\tframe errors %d\n", nhgetl(pkt+20));
814
		fprint(2, "\thardware overruns %d\n", nhgetl(pkt+24));
815
		fprint(2, "\tbuffer overruns %d\n", nhgetl(pkt+28));
816
		fprint(2, "\ttime-out errors %d\n", nhgetl(pkt+32));
817
		fprint(2, "\talignment errors %d\n", nhgetl(pkt+36));
818
		break;
819
 
820
	case Alinkinfo:
821
		fprint(2, "\tAlinkinfo peerid %d sendaccm 0x%ux recvaccm 0x%ux\n",
822
			nhgets(pkt+12), nhgetl(pkt+16),
823
			nhgetl(pkt+20));
824
		break;
825
	}
826
}
827
 
828
void
829
getaddrs(void)
830
{
831
	char buf[128];
832
	int fd, n;
833
 
834
	sprint(buf, "%s/local", tcpdir);
835
	if((fd = open(buf, OREAD)) < 0)
836
		myfatal("could not open %s: %r", buf);
837
	if((n = read(fd, buf, sizeof(buf))) < 0)
838
		myfatal("could not read %s: %r", buf);
839
	buf[n] = 0;
840
	parseip(localip, buf);
841
	close(fd);
842
 
843
	sprint(buf, "%s/remote", tcpdir);
844
	if((fd = open(buf, OREAD)) < 0)
845
		myfatal("could not open %s: %r", buf);
846
	if((n = read(fd, buf, sizeof(buf))) < 0)
847
		myfatal("could not read %s: %r", buf);
848
	buf[n] = 0;
849
	parseip(remoteip, buf);
850
	close(fd);
851
}
852
 
853
void
854
myfatal(char *fmt, ...)
855
{
856
	char sbuf[512];
857
	va_list arg;
858
	uchar buf[16];
859
 
860
	memset(buf, 0, sizeof(buf));
861
	hnputs(buf+0, sizeof(buf));	/* length */
862
	hnputs(buf+2, 1);		/* message type */
863
	hnputl(buf+4, Magic);		/* magic */
864
	hnputs(buf+8, Tstop);		/* op */
865
	buf[12] = 3;			/* local shutdown */
866
	write(ctlfd, buf, sizeof(buf));
867
 
868
	va_start(arg, fmt);
869
	vseprint(sbuf, sbuf+sizeof(sbuf), fmt, arg);
870
	va_end(arg);
871
 
872
	fprint(2, "fatal: %s\n", sbuf);
873
	threadexitsall(nil);
874
}