xref: /plan9-contrib/sys/src/cmd/ip/pptp.c (revision 912e5f5442636b48aaa52937edbb904e279d1987)
19a747e4fSDavid du Colombier /*
29a747e4fSDavid du Colombier  * Point-to-point Tunneling Protocol (PPTP)
39a747e4fSDavid du Colombier  * See RFC 2637, pptpd.c
49a747e4fSDavid du Colombier  */
59a747e4fSDavid du Colombier 
69a747e4fSDavid du Colombier #include <u.h>
79a747e4fSDavid du Colombier #include <libc.h>
89a747e4fSDavid du Colombier #include <bio.h>
99a747e4fSDavid du Colombier #include <ip.h>
109a747e4fSDavid du Colombier #include <thread.h>
119a747e4fSDavid du Colombier 
129a747e4fSDavid du Colombier int	ack;
139a747e4fSDavid du Colombier int	alarmed;
149a747e4fSDavid du Colombier int	ctlechotime;
159a747e4fSDavid du Colombier int	ctlfd;
169a747e4fSDavid du Colombier int	ctlrcvtime;
179a747e4fSDavid du Colombier int	debug;
189a747e4fSDavid du Colombier int	grefd;
199a747e4fSDavid du Colombier uchar localip[IPaddrlen];
209a747e4fSDavid du Colombier int	localwin;
21bedadc12SDavid du Colombier char	*keyspec;
229a747e4fSDavid du Colombier int	now;
239a747e4fSDavid du Colombier char	*pppnetmntpt;
249a747e4fSDavid du Colombier int	pid;
259a747e4fSDavid du Colombier Channel *pidchan;
269a747e4fSDavid du Colombier int	pppfd;
279a747e4fSDavid du Colombier int	primary;
289a747e4fSDavid du Colombier int	rack;
299a747e4fSDavid du Colombier Channel	*rdchan;
309a747e4fSDavid du Colombier int	rdexpect;
319a747e4fSDavid du Colombier int	remid;
329a747e4fSDavid du Colombier uchar remoteip[IPaddrlen];
339a747e4fSDavid du Colombier int	remwin;
349a747e4fSDavid du Colombier int	rseq;
359a747e4fSDavid du Colombier int	seq;
369a747e4fSDavid du Colombier char	tcpdir[40];
379a747e4fSDavid du Colombier Channel *tickchan;
389a747e4fSDavid du Colombier int	topppfd;
399a747e4fSDavid du Colombier 
409a747e4fSDavid du Colombier int	aread(int, int, void*, int);
419a747e4fSDavid du Colombier int	catchalarm(void*, char*);
429a747e4fSDavid du Colombier void	dumpctlpkt(uchar*);
439a747e4fSDavid du Colombier void	getaddrs(void);
449a747e4fSDavid du Colombier void	*emalloc(long);
459a747e4fSDavid du Colombier void	ewrite(int, void*, int);
469a747e4fSDavid du Colombier void	myfatal(char*, ...);
479a747e4fSDavid du Colombier #pragma varargck argpos myfatal 1
489a747e4fSDavid du Colombier int	pptp(char*);
499a747e4fSDavid du Colombier void	pushppp(int);
509a747e4fSDavid du Colombier void	recordack(int);
519a747e4fSDavid du Colombier int	schedack(int, uchar*, int);
529a747e4fSDavid du Colombier void	waitacks(void);
539a747e4fSDavid du Colombier 
549a747e4fSDavid du Colombier void
usage(void)559a747e4fSDavid du Colombier usage(void)
569a747e4fSDavid du Colombier {
57*912e5f54SDavid du Colombier 	fprint(2, "usage: ip/pptp [-Pd] [-k keyspec] [-x pppnetmntpt] [-w window] server\n");
589a747e4fSDavid du Colombier 	exits("usage");
599a747e4fSDavid du Colombier }
609a747e4fSDavid du Colombier 
619a747e4fSDavid du Colombier void
threadmain(int argc,char ** argv)629a747e4fSDavid du Colombier threadmain(int argc, char **argv)
639a747e4fSDavid du Colombier {
649a747e4fSDavid du Colombier 	int fd;
659a747e4fSDavid du Colombier 
669a747e4fSDavid du Colombier 	ARGBEGIN{
679a747e4fSDavid du Colombier 	case 'P':
689a747e4fSDavid du Colombier 		primary = 1;
699a747e4fSDavid du Colombier 		break;
709a747e4fSDavid du Colombier 	case 'd':
719a747e4fSDavid du Colombier 		debug++;
729a747e4fSDavid du Colombier 		break;
73bedadc12SDavid du Colombier 	case 'k':
74bedadc12SDavid du Colombier 		keyspec = EARGF(usage());
759a747e4fSDavid du Colombier 		break;
769a747e4fSDavid du Colombier 	case 'w':
779a747e4fSDavid du Colombier 		localwin = atoi(EARGF(usage()));
789a747e4fSDavid du Colombier 		break;
799a747e4fSDavid du Colombier 	case 'x':
809a747e4fSDavid du Colombier 		pppnetmntpt = EARGF(usage());
819a747e4fSDavid du Colombier 		break;
829a747e4fSDavid du Colombier 	default:
839a747e4fSDavid du Colombier 		usage();
849a747e4fSDavid du Colombier 	}ARGEND
859a747e4fSDavid du Colombier 
869a747e4fSDavid du Colombier 	if(argc != 1)
879a747e4fSDavid du Colombier 		usage();
889a747e4fSDavid du Colombier 
899a747e4fSDavid du Colombier 	fmtinstall('E', eipfmt);
909a747e4fSDavid du Colombier 	fmtinstall('I', eipfmt);
919a747e4fSDavid du Colombier 
929a747e4fSDavid du Colombier 	rfork(RFNOTEG);
939a747e4fSDavid du Colombier 	atnotify(catchalarm, 1);
949a747e4fSDavid du Colombier 	fd = pptp(argv[0]);
959a747e4fSDavid du Colombier 	pushppp(fd);
969a747e4fSDavid du Colombier 	exits(nil);
979a747e4fSDavid du Colombier }
989a747e4fSDavid du Colombier 
999a747e4fSDavid du Colombier int
catchalarm(void * a,char * msg)1009a747e4fSDavid du Colombier catchalarm(void *a, char *msg)
1019a747e4fSDavid du Colombier {
1029a747e4fSDavid du Colombier 	USED(a);
1039a747e4fSDavid du Colombier 
1049a747e4fSDavid du Colombier 	if(strstr(msg, "alarm")){
1059a747e4fSDavid du Colombier 		alarmed = 1;
1069a747e4fSDavid du Colombier 		return 1;
1079a747e4fSDavid du Colombier 	}
1089a747e4fSDavid du Colombier 	if(debug)
1099a747e4fSDavid du Colombier 		fprint(2, "note rcved: %s\n", msg);
1109a747e4fSDavid du Colombier 	return 0;
1119a747e4fSDavid du Colombier }
1129a747e4fSDavid du Colombier 
1139a747e4fSDavid du Colombier enum {
1149a747e4fSDavid du Colombier 	Stack	= 8192,
1159a747e4fSDavid du Colombier 
1169a747e4fSDavid du Colombier 	PptpProto	= 0x0100,
1179a747e4fSDavid du Colombier 
1189a747e4fSDavid du Colombier 	Magic	= 0x1a2b3c4d,
1199a747e4fSDavid du Colombier 	Window	= 16,		/* default window size */
1209a747e4fSDavid du Colombier 	Timeout	= 60,		/* timeout in seconds for control channel */
1219a747e4fSDavid du Colombier 	Pktsize = 2000,		/* maximum packet size */
1229a747e4fSDavid du Colombier 	Tick	= 500,		/* tick length in milliseconds */
1239a747e4fSDavid du Colombier 	Sendtimeout = 4,	/* in ticks */
1249a747e4fSDavid du Colombier 
1259a747e4fSDavid du Colombier 	Servertimeout = 5*60*1000/Tick,
1269a747e4fSDavid du Colombier 	Echointerval = 60*1000/Tick,
1279a747e4fSDavid du Colombier };
1289a747e4fSDavid du Colombier 
1299a747e4fSDavid du Colombier enum {
1309a747e4fSDavid du Colombier 	Syncframe	= 0x1,
1319a747e4fSDavid du Colombier 	Asyncframe	= 0x2,
1329a747e4fSDavid du Colombier 	Analog		= 0x1,
1339a747e4fSDavid du Colombier 	Digital		= 0x2,
1349a747e4fSDavid du Colombier 	Version		= 0x100,
1359a747e4fSDavid du Colombier };
1369a747e4fSDavid du Colombier 
1379a747e4fSDavid du Colombier enum {
1389a747e4fSDavid du Colombier 	Tstart		= 1,
1399a747e4fSDavid du Colombier 	Rstart		= 2,
1409a747e4fSDavid du Colombier 	Tstop		= 3,
1419a747e4fSDavid du Colombier 	Rstop		= 4,
1429a747e4fSDavid du Colombier 	Techo		= 5,
1439a747e4fSDavid du Colombier 	Recho		= 6,
1449a747e4fSDavid du Colombier 	Tcallout	= 7,
1459a747e4fSDavid du Colombier 	Rcallout	= 8,
1469a747e4fSDavid du Colombier 	Tcallreq	= 9,
1479a747e4fSDavid du Colombier 	Rcallreq	= 10,
1489a747e4fSDavid du Colombier 	Acallcon	= 11,
1499a747e4fSDavid du Colombier 	Tcallclear	= 12,
1509a747e4fSDavid du Colombier 	Acalldis	= 13,
1519a747e4fSDavid du Colombier 	Awaninfo	= 14,
1529a747e4fSDavid du Colombier 	Alinkinfo	= 15,
1539a747e4fSDavid du Colombier };
1549a747e4fSDavid du Colombier 
1559a747e4fSDavid du Colombier void
recho(uchar * in)1569a747e4fSDavid du Colombier recho(uchar *in)
1579a747e4fSDavid du Colombier {
1589a747e4fSDavid du Colombier 	uchar out[20];
1599a747e4fSDavid du Colombier 
1609a747e4fSDavid du Colombier 	if(nhgets(in) < 16)
1619a747e4fSDavid du Colombier 		return;
1629a747e4fSDavid du Colombier 
1639a747e4fSDavid du Colombier 	memset(out, 0, sizeof out);
1649a747e4fSDavid du Colombier 	hnputs(out, sizeof out);
1659a747e4fSDavid du Colombier 	hnputs(out+2, 1);
1669a747e4fSDavid du Colombier 	hnputl(out+4, Magic);
1679a747e4fSDavid du Colombier 	hnputs(out+8, Recho);
1689a747e4fSDavid du Colombier 	memmove(out+12, in+12, 4);
1699a747e4fSDavid du Colombier 	out[16] = 1;
1709a747e4fSDavid du Colombier 
1719a747e4fSDavid du Colombier 	ewrite(ctlfd, out, sizeof out);
1729a747e4fSDavid du Colombier }
1739a747e4fSDavid du Colombier 
1749a747e4fSDavid du Colombier void
sendecho(void)1759a747e4fSDavid du Colombier sendecho(void)
1769a747e4fSDavid du Colombier {
1779a747e4fSDavid du Colombier 	uchar out[16];
1789a747e4fSDavid du Colombier 
1799a747e4fSDavid du Colombier 	ctlechotime = now;
1809a747e4fSDavid du Colombier 	memset(out, 0, sizeof out);
1819a747e4fSDavid du Colombier 	hnputs(out, sizeof out);
1829a747e4fSDavid du Colombier 	hnputs(out+2, 1);
1839a747e4fSDavid du Colombier 	hnputl(out+4, Magic);
1849a747e4fSDavid du Colombier 	hnputs(out+8, Techo);
1859a747e4fSDavid du Colombier 
1869a747e4fSDavid du Colombier 	ewrite(ctlfd, out, sizeof out);
1879a747e4fSDavid du Colombier }
1889a747e4fSDavid du Colombier 
1899a747e4fSDavid du Colombier void
pptpctlproc(void *)1909a747e4fSDavid du Colombier pptpctlproc(void*)
1919a747e4fSDavid du Colombier {
1929a747e4fSDavid du Colombier 	uchar pkt[1600], *p;
1939a747e4fSDavid du Colombier 	int len;
1949a747e4fSDavid du Colombier 
1959a747e4fSDavid du Colombier 	for(;;){
1969a747e4fSDavid du Colombier 		if(readn(ctlfd, pkt, 2) != 2)
1979a747e4fSDavid du Colombier 			myfatal("pptpread: %r");
1989a747e4fSDavid du Colombier 		len = nhgets(pkt);
199439478acSDavid du Colombier 		if(len < 12 || len+2 >= sizeof pkt)
2009a747e4fSDavid du Colombier 			myfatal("pptpread: bad length %d", len);
2019a747e4fSDavid du Colombier 		if(readn(ctlfd, pkt+2, len-2) != len-2)
2029a747e4fSDavid du Colombier 			myfatal("pptpread: %r");
2039a747e4fSDavid du Colombier 		if(nhgetl(pkt+4) != Magic)
2049a747e4fSDavid du Colombier 			myfatal("pptpread bad magic");
2059a747e4fSDavid du Colombier 		if(nhgets(pkt+2) != 1)
2069a747e4fSDavid du Colombier 			myfatal("pptpread bad message type");
2079a747e4fSDavid du Colombier 		if(debug)
2089a747e4fSDavid du Colombier 			dumpctlpkt(pkt);
2099a747e4fSDavid du Colombier 		ctlrcvtime = now;
2109a747e4fSDavid du Colombier 
2119a747e4fSDavid du Colombier 		switch(nhgets(pkt+8)){
2129a747e4fSDavid du Colombier 		case Tstart:
2139a747e4fSDavid du Colombier 		case Tstop:
2149a747e4fSDavid du Colombier 		case Tcallout:
2159a747e4fSDavid du Colombier 		case Tcallreq:
2169a747e4fSDavid du Colombier 		case Tcallclear:
2179a747e4fSDavid du Colombier 		case Acallcon:
2189a747e4fSDavid du Colombier 		case Acalldis:
2199a747e4fSDavid du Colombier 		case Awaninfo:
2209a747e4fSDavid du Colombier 			myfatal("unexpected msg type %d", nhgets(pkt+8));
2219a747e4fSDavid du Colombier 		case Techo:
2229a747e4fSDavid du Colombier 			recho(pkt);
2239a747e4fSDavid du Colombier 			break;
2249a747e4fSDavid du Colombier 		case Recho:
2259a747e4fSDavid du Colombier 			break;
2269a747e4fSDavid du Colombier 		case Rstart:
2279a747e4fSDavid du Colombier 		case Rstop:
2289a747e4fSDavid du Colombier 		case Rcallout:
2299a747e4fSDavid du Colombier 		case Rcallreq:
2309a747e4fSDavid du Colombier 			if(rdexpect != nhgets(pkt+8))
2319a747e4fSDavid du Colombier 				continue;
2329a747e4fSDavid du Colombier 			p = emalloc(len);
2339a747e4fSDavid du Colombier 			memmove(p, pkt, len);
2349a747e4fSDavid du Colombier 			sendp(rdchan, p);
2359a747e4fSDavid du Colombier 			break;
2369a747e4fSDavid du Colombier 		case Alinkinfo:
2379a747e4fSDavid du Colombier 			myfatal("cannot change ppp params on the fly");
2389a747e4fSDavid du Colombier 		}
2399a747e4fSDavid du Colombier 	}
2409a747e4fSDavid du Colombier }
2419a747e4fSDavid du Colombier 
2429a747e4fSDavid du Colombier enum {
2439a747e4fSDavid du Colombier 	Seqnum = 0x1000,
2449a747e4fSDavid du Colombier 	Acknum = 0x0080,
2459a747e4fSDavid du Colombier 
2469a747e4fSDavid du Colombier 	GrePPP = 0x880B,
2479a747e4fSDavid du Colombier };
2489a747e4fSDavid du Colombier 
2499a747e4fSDavid du Colombier void
grereadproc(void *)2509a747e4fSDavid du Colombier grereadproc(void*)
2519a747e4fSDavid du Colombier {
2529a747e4fSDavid du Colombier 	int datoff, flags, len, n, pass;
2539a747e4fSDavid du Colombier 	uchar pkt[1600];
2549a747e4fSDavid du Colombier 	uchar src[IPaddrlen], dst[IPaddrlen];
2559a747e4fSDavid du Colombier 
2569a747e4fSDavid du Colombier 	rfork(RFFDG);
2579a747e4fSDavid du Colombier 	close(pppfd);
2589a747e4fSDavid du Colombier 	sendul(pidchan, getpid());
2599a747e4fSDavid du Colombier 
2609a747e4fSDavid du Colombier 	while((n = read(grefd, pkt, sizeof pkt)) > 0){
2619a747e4fSDavid du Colombier 		if(n == sizeof pkt)
2629a747e4fSDavid du Colombier 			myfatal("gre pkt buffer too small");
2639a747e4fSDavid du Colombier 		if(n < 16){
2649a747e4fSDavid du Colombier 			if(debug)
2659a747e4fSDavid du Colombier 				fprint(2, "small pkt len %d ignored\n", n);
2669a747e4fSDavid du Colombier 			continue;
2679a747e4fSDavid du Colombier 		}
2689a747e4fSDavid du Colombier 		v4tov6(src, pkt);
2699a747e4fSDavid du Colombier 		v4tov6(dst, pkt+4);
2709a747e4fSDavid du Colombier 		if(ipcmp(src, remoteip) != 0 || ipcmp(dst, localip) != 0)
2719a747e4fSDavid du Colombier 			myfatal("%I: gre read bad address src=%I dst=%I",
2729a747e4fSDavid du Colombier 				remoteip, src, dst);
2739a747e4fSDavid du Colombier 		if(nhgets(pkt+10) != GrePPP)
2749a747e4fSDavid du Colombier 			myfatal("%I: gre read bad protocol 0x%x",
2759a747e4fSDavid du Colombier 				remoteip, nhgets(pkt+10));
2769a747e4fSDavid du Colombier 
2779a747e4fSDavid du Colombier 		flags = nhgets(pkt+8);
2789a747e4fSDavid du Colombier 		if((flags&0xEF7F) != 0x2001){
2799a747e4fSDavid du Colombier 			if(debug)
2809a747e4fSDavid du Colombier 				fprint(2, "bad flags in gre hdr 0x%x\n", flags);
2819a747e4fSDavid du Colombier 			continue;
2829a747e4fSDavid du Colombier 		}
2839a747e4fSDavid du Colombier 		datoff = 8+8;
2849a747e4fSDavid du Colombier 		pass = 0;
2859a747e4fSDavid du Colombier 		len = nhgets(pkt+8+4);
2869a747e4fSDavid du Colombier 		if(len > n-datoff){
2879a747e4fSDavid du Colombier 			fprint(2, "bad payload length %d > %d\n",
2889a747e4fSDavid du Colombier 				len, n-datoff);
2899a747e4fSDavid du Colombier 			continue;
2909a747e4fSDavid du Colombier 		}
2919a747e4fSDavid du Colombier 		if(flags&Seqnum)
2929a747e4fSDavid du Colombier 			datoff += 4;
2939a747e4fSDavid du Colombier 		if(flags&Acknum){
2949a747e4fSDavid du Colombier 			recordack(nhgetl(pkt+datoff));
2959a747e4fSDavid du Colombier 			datoff += 4;
2969a747e4fSDavid du Colombier 		}
2979a747e4fSDavid du Colombier 		if(flags&Seqnum)
2989a747e4fSDavid du Colombier 			pass = schedack(nhgetl(pkt+8+8), pkt+datoff, len);
2999a747e4fSDavid du Colombier 		if(debug)
3009a747e4fSDavid du Colombier 			fprint(2, "got gre callid %d len %d flag 0x%x pass %d seq %d rseq %d\n", nhgets(pkt+8+6),
3019a747e4fSDavid du Colombier 				len, flags, pass, nhgetl(pkt+8+8), rseq);
3029a747e4fSDavid du Colombier 	}
3039a747e4fSDavid du Colombier 	threadexits(nil);
3049a747e4fSDavid du Colombier }
3059a747e4fSDavid du Colombier 
3069a747e4fSDavid du Colombier void
pppreadproc(void *)3079a747e4fSDavid du Colombier pppreadproc(void*)
3089a747e4fSDavid du Colombier {
3099a747e4fSDavid du Colombier 	int n, myrseq;
3109a747e4fSDavid du Colombier 	uchar pkt[1600];
3119a747e4fSDavid du Colombier 	enum {
3129a747e4fSDavid du Colombier 		Hdr = 8+16,
3139a747e4fSDavid du Colombier 	};
3149a747e4fSDavid du Colombier 
3159a747e4fSDavid du Colombier 	rfork(RFFDG);
3169a747e4fSDavid du Colombier 	close(pppfd);
3179a747e4fSDavid du Colombier 	sendul(pidchan, getpid());
3189a747e4fSDavid du Colombier 
3199a747e4fSDavid du Colombier 	while((n = read(topppfd, pkt+Hdr, sizeof pkt-Hdr)) > 0){
3209a747e4fSDavid du Colombier 		if(n == sizeof pkt-Hdr)
3219a747e4fSDavid du Colombier 			myfatal("ppp pkt buffer too small");
3229a747e4fSDavid du Colombier 		v6tov4(pkt+0, localip);
3239a747e4fSDavid du Colombier 		v6tov4(pkt+4, remoteip);
3249a747e4fSDavid du Colombier 		hnputs(pkt+8, 0x2001 | Seqnum | Acknum);
3259a747e4fSDavid du Colombier 		hnputs(pkt+10, GrePPP);
3269a747e4fSDavid du Colombier 		hnputs(pkt+12, n);
3279a747e4fSDavid du Colombier 		hnputs(pkt+14, remid);
3289a747e4fSDavid du Colombier 		hnputl(pkt+16, ++seq);
3299a747e4fSDavid du Colombier 		myrseq = rseq;
3309a747e4fSDavid du Colombier 		hnputl(pkt+20, myrseq);
3319a747e4fSDavid du Colombier 		rack = myrseq;
3329a747e4fSDavid du Colombier 		if(debug)
3339a747e4fSDavid du Colombier 			fprint(2, "wrote gre callid %d len %d flag 0x%x seq %d rseq %d\n", nhgets(pkt+8+6),
3349a747e4fSDavid du Colombier 				n, nhgets(pkt+8), nhgetl(pkt+16), nhgetl(pkt+20));
3359a747e4fSDavid du Colombier 		if(write(grefd, pkt, n+Hdr) != n+Hdr)
3369a747e4fSDavid du Colombier 			myfatal("gre write: %r");
3379a747e4fSDavid du Colombier 		waitacks();
3389a747e4fSDavid du Colombier 	}
3399a747e4fSDavid du Colombier 	threadexits(nil);
3409a747e4fSDavid du Colombier }
3419a747e4fSDavid du Colombier 
3429a747e4fSDavid du Colombier void
sendack(void)3439a747e4fSDavid du Colombier sendack(void)
3449a747e4fSDavid du Colombier {
3459a747e4fSDavid du Colombier 	int myrseq;
3469a747e4fSDavid du Colombier 	uchar pkt[20];
3479a747e4fSDavid du Colombier 
3489a747e4fSDavid du Colombier 	v6tov4(pkt+0, localip);
3499a747e4fSDavid du Colombier 	v6tov4(pkt+4, remoteip);
3509a747e4fSDavid du Colombier 	hnputs(pkt+8, 0x2001 | Acknum);
3519a747e4fSDavid du Colombier 	hnputs(pkt+10, GrePPP);
3529a747e4fSDavid du Colombier 	hnputs(pkt+12, 0);
3539a747e4fSDavid du Colombier 	hnputs(pkt+14, remid);
3549a747e4fSDavid du Colombier 	myrseq = rseq;
3559a747e4fSDavid du Colombier 	rack = myrseq;
3569a747e4fSDavid du Colombier 	hnputs(pkt+16, myrseq);
3579a747e4fSDavid du Colombier 
3589a747e4fSDavid du Colombier 	if(write(grefd, pkt, sizeof pkt) != sizeof pkt)
3599a747e4fSDavid du Colombier 		myfatal("gre write: %r");
3609a747e4fSDavid du Colombier }
3619a747e4fSDavid du Colombier 
3629a747e4fSDavid du Colombier int
schedack(int n,uchar * dat,int len)3639a747e4fSDavid du Colombier schedack(int n, uchar *dat, int len)
3649a747e4fSDavid du Colombier {
3659a747e4fSDavid du Colombier 	static uchar sdat[1600];
3669a747e4fSDavid du Colombier 	static int srseq, slen;
3679a747e4fSDavid du Colombier 
3689a747e4fSDavid du Colombier 	if(n-rseq <= 0){
3699a747e4fSDavid du Colombier 		fprint(2, "skipping pkt %d len %d, have %d\n", n, len, rseq);
3709a747e4fSDavid du Colombier 		return 0;
3719a747e4fSDavid du Colombier 	}
3729a747e4fSDavid du Colombier 
3739a747e4fSDavid du Colombier 	/* missed one pkt, maybe a swap happened, save pkt */
3749a747e4fSDavid du Colombier 	if(n==rseq+2){
3759a747e4fSDavid du Colombier 		memmove(sdat, dat, len);
3769a747e4fSDavid du Colombier 		slen = len;
3779a747e4fSDavid du Colombier 		srseq = n;
3789a747e4fSDavid du Colombier 		return 0;
3799a747e4fSDavid du Colombier 	}
3809a747e4fSDavid du Colombier 
3819a747e4fSDavid du Colombier 	if(n-rseq > 1){
3829a747e4fSDavid du Colombier 		if(slen && srseq == n-1){
3839a747e4fSDavid du Colombier 			fprint(2, "reswapped pkts %d and %d\n", srseq, n);
3849a747e4fSDavid du Colombier 			write(topppfd, sdat, slen);
3859a747e4fSDavid du Colombier 			slen = 0;
3869a747e4fSDavid du Colombier 		}else
3879a747e4fSDavid du Colombier 			fprint(2, "missed pkts %d-%d, got %d len %d\n", rseq+1, n-1, n, len);
3889a747e4fSDavid du Colombier 	}
3899a747e4fSDavid du Colombier 	write(topppfd, dat, len);
3909a747e4fSDavid du Colombier 	rseq = n;
3919a747e4fSDavid du Colombier 
3929a747e4fSDavid du Colombier 	/* send ack if we haven't recently */
3939a747e4fSDavid du Colombier 	if((int)(rseq-rack) > (localwin>>1))
3949a747e4fSDavid du Colombier 		sendack();
3959a747e4fSDavid du Colombier 
3969a747e4fSDavid du Colombier 	return 1;
3979a747e4fSDavid du Colombier }
3989a747e4fSDavid du Colombier 
3999a747e4fSDavid du Colombier void
gretimeoutproc(void *)4009a747e4fSDavid du Colombier gretimeoutproc(void*)
4019a747e4fSDavid du Colombier {
4029a747e4fSDavid du Colombier 	for(;;){
4039a747e4fSDavid du Colombier 		sleep(Tick);
4049a747e4fSDavid du Colombier 		now++;
4059a747e4fSDavid du Colombier 		nbsendul(tickchan, now);
4069a747e4fSDavid du Colombier 		if(now - ctlrcvtime > Servertimeout)
4079a747e4fSDavid du Colombier 			myfatal("server timeout");
4089a747e4fSDavid du Colombier 		if(now - ctlechotime > Echointerval)
4099a747e4fSDavid du Colombier 			sendecho();
4109a747e4fSDavid du Colombier 	}
4119a747e4fSDavid du Colombier }
4129a747e4fSDavid du Colombier 
4139a747e4fSDavid du Colombier void
recordack(int n)4149a747e4fSDavid du Colombier recordack(int n)
4159a747e4fSDavid du Colombier {
4169a747e4fSDavid du Colombier 	ack = n;
4179a747e4fSDavid du Colombier }
4189a747e4fSDavid du Colombier 
4199a747e4fSDavid du Colombier void
waitacks(void)4209a747e4fSDavid du Colombier waitacks(void)
4219a747e4fSDavid du Colombier {
422b85a8364SDavid du Colombier /*
4239a747e4fSDavid du Colombier 	int start;
4249a747e4fSDavid du Colombier 
4259a747e4fSDavid du Colombier 	start = now;
4269a747e4fSDavid du Colombier 	while(seq-ack > remwin && now-start < Sendtimeout){
4279a747e4fSDavid du Colombier 		print("seq %d ack %d remwin %d now %d start %d\n",
4289a747e4fSDavid du Colombier 			seq, ack, remwin, now, start);
4299a747e4fSDavid du Colombier 		recvul(tickchan);
4309a747e4fSDavid du Colombier 	}
431b85a8364SDavid du Colombier */
4329a747e4fSDavid du Colombier }
4339a747e4fSDavid du Colombier 
4349a747e4fSDavid du Colombier void
tstart(void)4359a747e4fSDavid du Colombier tstart(void)
4369a747e4fSDavid du Colombier {
4379a747e4fSDavid du Colombier 	char *name;
4389a747e4fSDavid du Colombier 	uchar pkt[200], *rpkt;
4399a747e4fSDavid du Colombier 
4409a747e4fSDavid du Colombier 	memset(pkt, 0, sizeof pkt);
4419a747e4fSDavid du Colombier 
4429a747e4fSDavid du Colombier 	hnputs(pkt+0, 156);
4439a747e4fSDavid du Colombier 	hnputs(pkt+2, 1);
4449a747e4fSDavid du Colombier 	hnputl(pkt+4, Magic);
4459a747e4fSDavid du Colombier 	hnputs(pkt+8, Tstart);
4469a747e4fSDavid du Colombier 	hnputs(pkt+12, PptpProto);
4479a747e4fSDavid du Colombier 	hnputl(pkt+16, 1);
4489a747e4fSDavid du Colombier 	hnputl(pkt+20, 1);
4499a747e4fSDavid du Colombier 	hnputs(pkt+24, 1);
4509a747e4fSDavid du Colombier 	name = sysname();
4519a747e4fSDavid du Colombier 	if(name == nil)
4529a747e4fSDavid du Colombier 		name = "gnot";
4539a747e4fSDavid du Colombier 	strcpy((char*)pkt+28, name);
4549a747e4fSDavid du Colombier 	strcpy((char*)pkt+92, "plan 9");
4559a747e4fSDavid du Colombier 
4569a747e4fSDavid du Colombier 	if(debug)
4579a747e4fSDavid du Colombier 		dumpctlpkt(pkt);
4589a747e4fSDavid du Colombier 
4599a747e4fSDavid du Colombier 	rdexpect = Rstart;
4609a747e4fSDavid du Colombier 	ewrite(ctlfd, pkt, 156);
4619a747e4fSDavid du Colombier 
4629a747e4fSDavid du Colombier 	rpkt = recvp(rdchan);
4639a747e4fSDavid du Colombier 	if(rpkt == nil)
4649a747e4fSDavid du Colombier 		myfatal("recvp: %r");
4659a747e4fSDavid du Colombier 	if(nhgets(rpkt) != 156)
4669a747e4fSDavid du Colombier 		myfatal("Rstart wrong length %d != 156", nhgets(rpkt));
4679a747e4fSDavid du Colombier 	if(rpkt[14] != 1)
4689a747e4fSDavid du Colombier 		myfatal("Rstart error %d", rpkt[15]);
4699a747e4fSDavid du Colombier 	free(rpkt);
4709a747e4fSDavid du Colombier }
4719a747e4fSDavid du Colombier 
4729a747e4fSDavid du Colombier void
tcallout(void)4739a747e4fSDavid du Colombier tcallout(void)
4749a747e4fSDavid du Colombier {
4759a747e4fSDavid du Colombier 	uchar pkt[200], *rpkt;
4769a747e4fSDavid du Colombier 
4779a747e4fSDavid du Colombier 	pid = getpid();
4789a747e4fSDavid du Colombier 
4799a747e4fSDavid du Colombier 	memset(pkt, 0, sizeof pkt);
4809a747e4fSDavid du Colombier 	hnputs(pkt+0, 168);
4819a747e4fSDavid du Colombier 	hnputs(pkt+2, 1);
4829a747e4fSDavid du Colombier 	hnputl(pkt+4, Magic);
4839a747e4fSDavid du Colombier 	hnputs(pkt+8, Tcallout);
4849a747e4fSDavid du Colombier 
4859a747e4fSDavid du Colombier 	hnputl(pkt+16, 56000);
4869a747e4fSDavid du Colombier 	hnputl(pkt+20, 768000);
4879a747e4fSDavid du Colombier 	hnputl(pkt+24, 3);
4889a747e4fSDavid du Colombier 	hnputl(pkt+28, 3);
4899a747e4fSDavid du Colombier 	if(localwin == 0)
4909a747e4fSDavid du Colombier 		localwin = Window;
4919a747e4fSDavid du Colombier 	hnputs(pkt+32, localwin);
4929a747e4fSDavid du Colombier 
4939a747e4fSDavid du Colombier 	if(debug)
4949a747e4fSDavid du Colombier 		dumpctlpkt(pkt);
4959a747e4fSDavid du Colombier 
4969a747e4fSDavid du Colombier 	rdexpect = Rcallout;
4979a747e4fSDavid du Colombier 	ewrite(ctlfd, pkt, 168);
4989a747e4fSDavid du Colombier 
4999a747e4fSDavid du Colombier 	rpkt = recvp(rdchan);
5009a747e4fSDavid du Colombier 	if(rpkt == nil)
5019a747e4fSDavid du Colombier 		myfatal("recvp: %r");
5029a747e4fSDavid du Colombier 	if(nhgets(rpkt) != 32)
5039a747e4fSDavid du Colombier 		myfatal("Rcallreq wrong length %d != 32", nhgets(rpkt));
5049a747e4fSDavid du Colombier 	if(rpkt[16] != 1)
5059a747e4fSDavid du Colombier 		myfatal("Rcallreq error %d", rpkt[17]);
5069a747e4fSDavid du Colombier 	remid = nhgets(pkt+12);
5079a747e4fSDavid du Colombier 	remwin = nhgets(pkt+24);
5089a747e4fSDavid du Colombier 	free(rpkt);
5099a747e4fSDavid du Colombier }
5109a747e4fSDavid du Colombier 
5119a747e4fSDavid du Colombier /*
5129a747e4fSDavid du Colombier void
5139a747e4fSDavid du Colombier tcallreq(void)
5149a747e4fSDavid du Colombier {
5159a747e4fSDavid du Colombier 	uchar pkt[200], *rpkt;
5169a747e4fSDavid du Colombier 
5179a747e4fSDavid du Colombier 	pid = getpid();
5189a747e4fSDavid du Colombier 
5199a747e4fSDavid du Colombier 	memset(pkt, 0, sizeof pkt);
5209a747e4fSDavid du Colombier 	hnputs(pkt+0, 220);
5219a747e4fSDavid du Colombier 	hnputs(pkt+2, 1);
5229a747e4fSDavid du Colombier 	hnputl(pkt+4, Magic);
5239a747e4fSDavid du Colombier 	hnputs(pkt+8, Tcallreq);
5249a747e4fSDavid du Colombier 
5259a747e4fSDavid du Colombier 	if(debug)
5269a747e4fSDavid du Colombier 		dumpctlpkt(pkt);
5279a747e4fSDavid du Colombier 
5289a747e4fSDavid du Colombier 	rdexpect = Rcallreq;
5299a747e4fSDavid du Colombier 	ewrite(ctlfd, pkt, 220);
5309a747e4fSDavid du Colombier 
5319a747e4fSDavid du Colombier 	rpkt = recvp(rdchan);
5329a747e4fSDavid du Colombier 	if(rpkt == nil)
5339a747e4fSDavid du Colombier 		myfatal("recvp: %r");
5349a747e4fSDavid du Colombier 	if(nhgets(rpkt) != 24)
5359a747e4fSDavid du Colombier 		myfatal("Rcallreq wrong length %d != 24", nhgets(rpkt));
5369a747e4fSDavid du Colombier 	if(rpkt[16] != 1)
5379a747e4fSDavid du Colombier 		myfatal("Rcallreq error %d", rpkt[17]);
5389a747e4fSDavid du Colombier 	remid = nhgets(pkt+12);
5399a747e4fSDavid du Colombier 	remwin = nhgets(pkt+18);
5409a747e4fSDavid du Colombier 	free(rpkt);
5419a747e4fSDavid du Colombier }
5429a747e4fSDavid du Colombier 
5439a747e4fSDavid du Colombier void
5449a747e4fSDavid du Colombier acallcon(void)
5459a747e4fSDavid du Colombier {
5469a747e4fSDavid du Colombier 	uchar pkt[200];
5479a747e4fSDavid du Colombier 
5489a747e4fSDavid du Colombier 	memset(pkt, 0, sizeof pkt);
5499a747e4fSDavid du Colombier 	hnputs(pkt+0, 28);
5509a747e4fSDavid du Colombier 	hnputs(pkt+2, 1);
5519a747e4fSDavid du Colombier 	hnputl(pkt+4, Magic);
5529a747e4fSDavid du Colombier 	hnputs(pkt+8, Acallcon);
5539a747e4fSDavid du Colombier 	hnputs(pkt+12, remid);
5549a747e4fSDavid du Colombier 	if(localwin == 0)
5559a747e4fSDavid du Colombier 		localwin = Window;
5569a747e4fSDavid du Colombier 	hnputs(pkt+20, localwin);
5579a747e4fSDavid du Colombier 	hnputl(pkt+24, 1);
5589a747e4fSDavid du Colombier 
5599a747e4fSDavid du Colombier 	if(debug)
5609a747e4fSDavid du Colombier 		dumpctlpkt(pkt);
5619a747e4fSDavid du Colombier 
5629a747e4fSDavid du Colombier 	ewrite(ctlfd, pkt, 28);
5639a747e4fSDavid du Colombier }
5649a747e4fSDavid du Colombier */
5659a747e4fSDavid du Colombier 
5669a747e4fSDavid du Colombier int
pptp(char * addr)5679a747e4fSDavid du Colombier pptp(char *addr)
5689a747e4fSDavid du Colombier {
5699a747e4fSDavid du Colombier 	int p[2];
5709a747e4fSDavid du Colombier 	char greaddr[128];
5719a747e4fSDavid du Colombier 
5729a747e4fSDavid du Colombier 	addr = netmkaddr(addr, "net", "pptp");
5739a747e4fSDavid du Colombier 	ctlfd = dial(addr, nil, tcpdir, nil);
5749a747e4fSDavid du Colombier 	if(ctlfd < 0)
5759a747e4fSDavid du Colombier 		myfatal("dial %s: %r", addr);
5769a747e4fSDavid du Colombier  	getaddrs();
5779a747e4fSDavid du Colombier 
5789a747e4fSDavid du Colombier 	rdchan = chancreate(sizeof(void*), 0);
5799a747e4fSDavid du Colombier 	proccreate(pptpctlproc, nil, Stack);
5809a747e4fSDavid du Colombier 
5819a747e4fSDavid du Colombier 	tstart();
5829a747e4fSDavid du Colombier 	tcallout();
5839a747e4fSDavid du Colombier 
5849a747e4fSDavid du Colombier 	if(pipe(p) < 0)
5859a747e4fSDavid du Colombier 		myfatal("pipe: %r");
5869a747e4fSDavid du Colombier 
5879a747e4fSDavid du Colombier 	pppfd = p[0];
5889a747e4fSDavid du Colombier 	topppfd = p[1];
5899a747e4fSDavid du Colombier 
5909a747e4fSDavid du Colombier 	strcpy(greaddr, tcpdir);
5919a747e4fSDavid du Colombier 	*strrchr(greaddr, '/') = '\0';
5929a747e4fSDavid du Colombier 	sprint(strrchr(greaddr, '/')+1, "gre!%I!%d", remoteip, GrePPP);
5939a747e4fSDavid du Colombier 
5949a747e4fSDavid du Colombier 	print("local %I remote %I gre %s remid %d remwin %d\n",
5959a747e4fSDavid du Colombier 		localip, remoteip, greaddr, remid, remwin);
5969a747e4fSDavid du Colombier 
5979a747e4fSDavid du Colombier 	grefd = dial(greaddr, nil, nil, nil);
5989a747e4fSDavid du Colombier 	if(grefd < 0)
5999a747e4fSDavid du Colombier 		myfatal("dial gre: %r");
6009a747e4fSDavid du Colombier 
6019a747e4fSDavid du Colombier 	tickchan = chancreate(sizeof(int), 0);
6029a747e4fSDavid du Colombier 	proccreate(gretimeoutproc, nil, Stack);
6039a747e4fSDavid du Colombier 
6049a747e4fSDavid du Colombier 	pidchan = chancreate(sizeof(int), 0);
6059a747e4fSDavid du Colombier 	proccreate(grereadproc, nil, Stack);
6069a747e4fSDavid du Colombier 	recvul(pidchan);
6079a747e4fSDavid du Colombier 	proccreate(pppreadproc, nil, Stack);
6089a747e4fSDavid du Colombier 	recvul(pidchan);
6099a747e4fSDavid du Colombier 
6109a747e4fSDavid du Colombier 	close(topppfd);
6119a747e4fSDavid du Colombier 	return pppfd;
6129a747e4fSDavid du Colombier }
6139a747e4fSDavid du Colombier 
6149a747e4fSDavid du Colombier void
pushppp(int fd)6159a747e4fSDavid du Colombier pushppp(int fd)
6169a747e4fSDavid du Colombier {
6179a747e4fSDavid du Colombier 	char *argv[16];
6189a747e4fSDavid du Colombier 	int argc;
6199a747e4fSDavid du Colombier 
6209a747e4fSDavid du Colombier 	argc = 0;
6219a747e4fSDavid du Colombier 	argv[argc++] = "/bin/ip/ppp";
6229a747e4fSDavid du Colombier 	argv[argc++] = "-C";
6239a747e4fSDavid du Colombier 	argv[argc++] = "-m1450";
6249a747e4fSDavid du Colombier 	if(debug)
6259a747e4fSDavid du Colombier 		argv[argc++] = "-d";
6269a747e4fSDavid du Colombier 	if(primary)
6279a747e4fSDavid du Colombier 		argv[argc++] = "-P";
6289a747e4fSDavid du Colombier 	if(pppnetmntpt){
6299a747e4fSDavid du Colombier 		argv[argc++] = "-x";
6309a747e4fSDavid du Colombier 		argv[argc++] = pppnetmntpt;
6319a747e4fSDavid du Colombier 	}
632bedadc12SDavid du Colombier 	if(keyspec){
633bedadc12SDavid du Colombier 		argv[argc++] = "-k";
634bedadc12SDavid du Colombier 		argv[argc++] = keyspec;
6359a747e4fSDavid du Colombier 	}
6369a747e4fSDavid du Colombier 	argv[argc] = nil;
6379a747e4fSDavid du Colombier 
6389a747e4fSDavid du Colombier 	switch(fork()){
6399a747e4fSDavid du Colombier 	case -1:
6409a747e4fSDavid du Colombier 		myfatal("fork: %r");
6419a747e4fSDavid du Colombier 	default:
6429a747e4fSDavid du Colombier 		return;
6439a747e4fSDavid du Colombier 	case 0:
6449a747e4fSDavid du Colombier 		dup(fd, 0);
6459a747e4fSDavid du Colombier 		dup(fd, 1);
6469a747e4fSDavid du Colombier 		exec(argv[0], argv);
6479a747e4fSDavid du Colombier 		myfatal("exec: %r");
6489a747e4fSDavid du Colombier 	}
6499a747e4fSDavid du Colombier }
6509a747e4fSDavid du Colombier 
6519a747e4fSDavid du Colombier int
aread(int timeout,int fd,void * buf,int nbuf)6529a747e4fSDavid du Colombier aread(int timeout, int fd, void *buf, int nbuf)
6539a747e4fSDavid du Colombier {
6549a747e4fSDavid du Colombier 	int n;
6559a747e4fSDavid du Colombier 
6569a747e4fSDavid du Colombier 	alarmed = 0;
6579a747e4fSDavid du Colombier 	alarm(timeout);
6589a747e4fSDavid du Colombier 	n = read(fd, buf, nbuf);
6599a747e4fSDavid du Colombier 	alarm(0);
6609a747e4fSDavid du Colombier 	if(alarmed)
6619a747e4fSDavid du Colombier 		return -1;
6629a747e4fSDavid du Colombier 	if(n < 0)
6639a747e4fSDavid du Colombier 		myfatal("read: %r");
6649a747e4fSDavid du Colombier 	if(n == 0)
6659a747e4fSDavid du Colombier 		myfatal("short read");
6669a747e4fSDavid du Colombier 	return n;
6679a747e4fSDavid du Colombier }
6689a747e4fSDavid du Colombier 
6699a747e4fSDavid du Colombier void
ewrite(int fd,void * buf,int nbuf)6709a747e4fSDavid du Colombier ewrite(int fd, void *buf, int nbuf)
6719a747e4fSDavid du Colombier {
6729a747e4fSDavid du Colombier 	char e[ERRMAX], path[64];
6739a747e4fSDavid du Colombier 
6749a747e4fSDavid du Colombier 	if(write(fd, buf, nbuf) != nbuf){
6759a747e4fSDavid du Colombier 		rerrstr(e, sizeof e);
6769a747e4fSDavid du Colombier 		strcpy(path, "unknown");
6779a747e4fSDavid du Colombier 		fd2path(fd, path, sizeof path);
6789a747e4fSDavid du Colombier 		myfatal("write %d to %s: %s", nbuf, path, e);
6799a747e4fSDavid du Colombier 	}
6809a747e4fSDavid du Colombier }
6819a747e4fSDavid du Colombier 
6829a747e4fSDavid du Colombier void*
emalloc(long n)6839a747e4fSDavid du Colombier emalloc(long n)
6849a747e4fSDavid du Colombier {
6859a747e4fSDavid du Colombier 	void *v;
6869a747e4fSDavid du Colombier 
6879a747e4fSDavid du Colombier 	v = malloc(n);
6889a747e4fSDavid du Colombier 	if(v == nil)
6899a747e4fSDavid du Colombier 		myfatal("out of memory");
6909a747e4fSDavid du Colombier 	return v;
6919a747e4fSDavid du Colombier }
6929a747e4fSDavid du Colombier 
6939a747e4fSDavid du Colombier int
thread(void (* f)(void *),void * a)6949a747e4fSDavid du Colombier thread(void(*f)(void*), void *a)
6959a747e4fSDavid du Colombier {
6969a747e4fSDavid du Colombier 	int pid;
6979a747e4fSDavid du Colombier 	pid=rfork(RFNOWAIT|RFMEM|RFPROC);
6989a747e4fSDavid du Colombier 	if(pid < 0)
6999a747e4fSDavid du Colombier 		myfatal("rfork: %r");
7009a747e4fSDavid du Colombier 	if(pid != 0)
7019a747e4fSDavid du Colombier 		return pid;
7029a747e4fSDavid du Colombier 	(*f)(a);
7039a747e4fSDavid du Colombier 	_exits(nil);
7049a747e4fSDavid du Colombier 	return 0; // never reaches here
7059a747e4fSDavid du Colombier }
7069a747e4fSDavid du Colombier 
7079a747e4fSDavid du Colombier void
dumpctlpkt(uchar * pkt)7089a747e4fSDavid du Colombier dumpctlpkt(uchar *pkt)
7099a747e4fSDavid du Colombier {
7109a747e4fSDavid du Colombier 	fprint(2, "pkt len %d mtype %d cookie 0x%.8ux type %d\n",
7119a747e4fSDavid du Colombier 		nhgets(pkt), nhgets(pkt+2),
7129a747e4fSDavid du Colombier 		nhgetl(pkt+4), nhgets(pkt+8));
7139a747e4fSDavid du Colombier 
7149a747e4fSDavid du Colombier 	switch(nhgets(pkt+8)){
7159a747e4fSDavid du Colombier 	default:
7169a747e4fSDavid du Colombier 		fprint(2, "\tunknown type\n");
7179a747e4fSDavid du Colombier 		break;
7189a747e4fSDavid du Colombier 	case Tstart:
7199a747e4fSDavid du Colombier 		fprint(2, "\tTstart proto %d framing %d bearer %d maxchan %d firmware %d\n",
7209a747e4fSDavid du Colombier 			nhgets(pkt+12), nhgetl(pkt+16),
7219a747e4fSDavid du Colombier 			nhgetl(pkt+20), nhgets(pkt+24),
7229a747e4fSDavid du Colombier 			nhgets(pkt+26));
7239a747e4fSDavid du Colombier 		fprint(2, "\thost %.64s\n", (char*)pkt+28);
7249a747e4fSDavid du Colombier 		fprint(2, "\tvendor %.64s\n", (char*)pkt+92);
7259a747e4fSDavid du Colombier 		break;
7269a747e4fSDavid du Colombier 	case Rstart:
7279a747e4fSDavid du Colombier 		fprint(2, "\tRstart proto %d res %d err %d framing %d bearer %d maxchan %d firmware %d\n",
7289a747e4fSDavid du Colombier 			nhgets(pkt+12), pkt[14], pkt[15],
7299a747e4fSDavid du Colombier 			nhgetl(pkt+16),
7309a747e4fSDavid du Colombier 			nhgetl(pkt+20), nhgets(pkt+24),
7319a747e4fSDavid du Colombier 			nhgets(pkt+26));
7329a747e4fSDavid du Colombier 		fprint(2, "\thost %.64s\n", (char*)pkt+28);
7339a747e4fSDavid du Colombier 		fprint(2, "\tvendor %.64s\n", (char*)pkt+92);
7349a747e4fSDavid du Colombier 		break;
7359a747e4fSDavid du Colombier 
7369a747e4fSDavid du Colombier 	case Tstop:
7379a747e4fSDavid du Colombier 		fprint(2, "\tTstop reason %d\n", pkt[12]);
7389a747e4fSDavid du Colombier 		break;
7399a747e4fSDavid du Colombier 
7409a747e4fSDavid du Colombier 	case Rstop:
7419a747e4fSDavid du Colombier 		fprint(2, "\tRstop res %d err %d\n", pkt[12], pkt[13]);
7429a747e4fSDavid du Colombier 		break;
7439a747e4fSDavid du Colombier 
7449a747e4fSDavid du Colombier 	case Techo:
7459a747e4fSDavid du Colombier 		fprint(2, "\tTecho id %.8ux\n", nhgetl(pkt+12));
7469a747e4fSDavid du Colombier 		break;
7479a747e4fSDavid du Colombier 
7489a747e4fSDavid du Colombier 	case Recho:
7499a747e4fSDavid du Colombier 		fprint(2, "\tRecho id %.8ux res %d err %d\n", nhgetl(pkt+12), pkt[16], pkt[17]);
7509a747e4fSDavid du Colombier 		break;
7519a747e4fSDavid du Colombier 
7529a747e4fSDavid du Colombier 	case Tcallout:
7539a747e4fSDavid du Colombier 		fprint(2, "\tTcallout id %d serno %d bps %d-%d\n",
7549a747e4fSDavid du Colombier 			nhgets(pkt+12), nhgets(pkt+14),
7559a747e4fSDavid du Colombier 			nhgetl(pkt+16), nhgetl(pkt+20));
7569a747e4fSDavid du Colombier 		fprint(2, "\tbearer 0x%x framing 0x%x recvwin %d delay %d\n",
7579a747e4fSDavid du Colombier 			nhgetl(pkt+24), nhgetl(pkt+28),
7589a747e4fSDavid du Colombier 			nhgets(pkt+32), nhgets(pkt+34));
7599a747e4fSDavid du Colombier 		fprint(2, "\tphone len %d num %.64s\n",
7609a747e4fSDavid du Colombier 			nhgets(pkt+36), (char*)pkt+40);
7619a747e4fSDavid du Colombier 		fprint(2, "\tsubaddr %.64s\n", (char*)pkt+104);
7629a747e4fSDavid du Colombier 		break;
7639a747e4fSDavid du Colombier 
7649a747e4fSDavid du Colombier 	case Rcallout:
7659a747e4fSDavid du Colombier 		fprint(2, "\tRcallout id %d peerid %d res %d err %d cause %d\n",
7669a747e4fSDavid du Colombier 			nhgets(pkt+12), nhgets(pkt+14),
7679a747e4fSDavid du Colombier 			pkt[16], pkt[17], nhgets(pkt+18));
7689a747e4fSDavid du Colombier 		fprint(2, "\tconnect %d recvwin %d delay %d chan 0x%.8ux\n",
7699a747e4fSDavid du Colombier 			nhgetl(pkt+20), nhgets(pkt+24),
7709a747e4fSDavid du Colombier 			nhgets(pkt+26), nhgetl(pkt+28));
7719a747e4fSDavid du Colombier 		break;
7729a747e4fSDavid du Colombier 
7739a747e4fSDavid du Colombier 	case Tcallreq:
7749a747e4fSDavid du Colombier 		fprint(2, "\tTcallreq id %d serno %d bearer 0x%x id 0x%x\n",
7759a747e4fSDavid du Colombier 			nhgets(pkt+12), nhgets(pkt+14),
7769a747e4fSDavid du Colombier 			nhgetl(pkt+16), nhgetl(pkt+20));
7779a747e4fSDavid du Colombier 		fprint(2, "\tdialed len %d num %.64s\n",
7789a747e4fSDavid du Colombier 			nhgets(pkt+24), (char*)pkt+28);
7799a747e4fSDavid du Colombier 		fprint(2, "\tdialing len %d num %.64s\n",
7809a747e4fSDavid du Colombier 			nhgets(pkt+26), (char*)pkt+92);
7819a747e4fSDavid du Colombier 		fprint(2, "\tsubaddr %.64s\n", (char*)pkt+156);
7829a747e4fSDavid du Colombier 		break;
7839a747e4fSDavid du Colombier 
7849a747e4fSDavid du Colombier 	case Rcallreq:
7859a747e4fSDavid du Colombier 		fprint(2, "\tRcallout id %d peerid %d res %d err %d recvwin %d delay %d\n",
7869a747e4fSDavid du Colombier 			nhgets(pkt+12), nhgets(pkt+14),
7879a747e4fSDavid du Colombier 			pkt[16], pkt[17], nhgets(pkt+18),
7889a747e4fSDavid du Colombier 			nhgets(pkt+20));
7899a747e4fSDavid du Colombier 		break;
7909a747e4fSDavid du Colombier 
7919a747e4fSDavid du Colombier 	case Acallcon:
7929a747e4fSDavid du Colombier 		fprint(2, "\tAcallcon peerid %d connect %d recvwin %d delay %d framing 0x%x\n",
7939a747e4fSDavid du Colombier 			nhgets(pkt+12), nhgetl(pkt+16),
7949a747e4fSDavid du Colombier 			nhgets(pkt+20), nhgets(pkt+22),
7959a747e4fSDavid du Colombier 			nhgetl(pkt+24));
7969a747e4fSDavid du Colombier 		break;
7979a747e4fSDavid du Colombier 
7989a747e4fSDavid du Colombier 	case Tcallclear:
7999a747e4fSDavid du Colombier 		fprint(2, "\tTcallclear callid %d\n",
8009a747e4fSDavid du Colombier 			nhgets(pkt+12));
8019a747e4fSDavid du Colombier 		break;
8029a747e4fSDavid du Colombier 
8039a747e4fSDavid du Colombier 	case Acalldis:
8049a747e4fSDavid du Colombier 		fprint(2, "\tAcalldis callid %d res %d err %d cause %d\n",
8059a747e4fSDavid du Colombier 			nhgets(pkt+12), pkt[14], pkt[15],
8069a747e4fSDavid du Colombier 			nhgets(pkt+16));
8079a747e4fSDavid du Colombier 		fprint(2, "\tstats %.128s\n", (char*)pkt+20);
8089a747e4fSDavid du Colombier 		break;
8099a747e4fSDavid du Colombier 
8109a747e4fSDavid du Colombier 	case Awaninfo:
8119a747e4fSDavid du Colombier 		fprint(2, "\tAwaninfo peerid %d\n", nhgets(pkt+12));
8129a747e4fSDavid du Colombier 		fprint(2, "\tcrc errors %d\n", nhgetl(pkt+16));
8139a747e4fSDavid du Colombier 		fprint(2, "\tframe errors %d\n", nhgetl(pkt+20));
8149a747e4fSDavid du Colombier 		fprint(2, "\thardware overruns %d\n", nhgetl(pkt+24));
8159a747e4fSDavid du Colombier 		fprint(2, "\tbuffer overruns %d\n", nhgetl(pkt+28));
8169a747e4fSDavid du Colombier 		fprint(2, "\ttime-out errors %d\n", nhgetl(pkt+32));
8179a747e4fSDavid du Colombier 		fprint(2, "\talignment errors %d\n", nhgetl(pkt+36));
8189a747e4fSDavid du Colombier 		break;
8199a747e4fSDavid du Colombier 
8209a747e4fSDavid du Colombier 	case Alinkinfo:
8219a747e4fSDavid du Colombier 		fprint(2, "\tAlinkinfo peerid %d sendaccm 0x%ux recvaccm 0x%ux\n",
8229a747e4fSDavid du Colombier 			nhgets(pkt+12), nhgetl(pkt+16),
8239a747e4fSDavid du Colombier 			nhgetl(pkt+20));
8249a747e4fSDavid du Colombier 		break;
8259a747e4fSDavid du Colombier 	}
8269a747e4fSDavid du Colombier }
8279a747e4fSDavid du Colombier 
8289a747e4fSDavid du Colombier void
getaddrs(void)8299a747e4fSDavid du Colombier getaddrs(void)
8309a747e4fSDavid du Colombier {
8319a747e4fSDavid du Colombier 	char buf[128];
8329a747e4fSDavid du Colombier 	int fd, n;
8339a747e4fSDavid du Colombier 
8349a747e4fSDavid du Colombier 	sprint(buf, "%s/local", tcpdir);
8359a747e4fSDavid du Colombier 	if((fd = open(buf, OREAD)) < 0)
8369a747e4fSDavid du Colombier 		myfatal("could not open %s: %r", buf);
8379a747e4fSDavid du Colombier 	if((n = read(fd, buf, sizeof(buf))) < 0)
8389a747e4fSDavid du Colombier 		myfatal("could not read %s: %r", buf);
8399a747e4fSDavid du Colombier 	buf[n] = 0;
8409a747e4fSDavid du Colombier 	parseip(localip, buf);
8419a747e4fSDavid du Colombier 	close(fd);
8429a747e4fSDavid du Colombier 
8439a747e4fSDavid du Colombier 	sprint(buf, "%s/remote", tcpdir);
8449a747e4fSDavid du Colombier 	if((fd = open(buf, OREAD)) < 0)
8459a747e4fSDavid du Colombier 		myfatal("could not open %s: %r", buf);
8469a747e4fSDavid du Colombier 	if((n = read(fd, buf, sizeof(buf))) < 0)
8479a747e4fSDavid du Colombier 		myfatal("could not read %s: %r", buf);
8489a747e4fSDavid du Colombier 	buf[n] = 0;
8499a747e4fSDavid du Colombier 	parseip(remoteip, buf);
8509a747e4fSDavid du Colombier 	close(fd);
8519a747e4fSDavid du Colombier }
8529a747e4fSDavid du Colombier 
8539a747e4fSDavid du Colombier void
myfatal(char * fmt,...)8549a747e4fSDavid du Colombier myfatal(char *fmt, ...)
8559a747e4fSDavid du Colombier {
8569a747e4fSDavid du Colombier 	char sbuf[512];
8579a747e4fSDavid du Colombier 	va_list arg;
8589a747e4fSDavid du Colombier 	uchar buf[16];
8599a747e4fSDavid du Colombier 
8609a747e4fSDavid du Colombier 	memset(buf, 0, sizeof(buf));
8619a747e4fSDavid du Colombier 	hnputs(buf+0, sizeof(buf));	/* length */
8629a747e4fSDavid du Colombier 	hnputs(buf+2, 1);		/* message type */
8639a747e4fSDavid du Colombier 	hnputl(buf+4, Magic);		/* magic */
8649a747e4fSDavid du Colombier 	hnputs(buf+8, Tstop);		/* op */
8659a747e4fSDavid du Colombier 	buf[12] = 3;			/* local shutdown */
8669a747e4fSDavid du Colombier 	write(ctlfd, buf, sizeof(buf));
8679a747e4fSDavid du Colombier 
8689a747e4fSDavid du Colombier 	va_start(arg, fmt);
8699a747e4fSDavid du Colombier 	vseprint(sbuf, sbuf+sizeof(sbuf), fmt, arg);
8709a747e4fSDavid du Colombier 	va_end(arg);
8719a747e4fSDavid du Colombier 
8729a747e4fSDavid du Colombier 	fprint(2, "fatal: %s\n", sbuf);
8739a747e4fSDavid du Colombier 	threadexitsall(nil);
8749a747e4fSDavid du Colombier }
875