xref: /plan9/sys/src/cmd/ip/pptp.c (revision 912e5f5442636b48aaa52937edbb904e279d1987)
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
usage(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
threadmain(int argc,char ** argv)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
catchalarm(void * a,char * msg)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
recho(uchar * in)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
sendecho(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
pptpctlproc(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
grereadproc(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
pppreadproc(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
sendack(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
schedack(int n,uchar * dat,int len)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
gretimeoutproc(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
recordack(int n)414 recordack(int n)
415 {
416 	ack = n;
417 }
418 
419 void
waitacks(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
tstart(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
tcallout(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
pptp(char * addr)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
pushppp(int fd)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
aread(int timeout,int fd,void * buf,int nbuf)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
ewrite(int fd,void * buf,int nbuf)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*
emalloc(long n)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
thread(void (* f)(void *),void * a)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
dumpctlpkt(uchar * pkt)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
getaddrs(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
myfatal(char * fmt,...)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 }
875