xref: /plan9-contrib/sys/src/cmd/ip/pptpd.c (revision ea58ad6fbee60d5a3fca57ac646881779dd8f0ea)
17dd7cddfSDavid du Colombier #include <u.h>
27dd7cddfSDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <bio.h>
47dd7cddfSDavid du Colombier #include <ip.h>
57dd7cddfSDavid du Colombier 
67dd7cddfSDavid du Colombier #define	LOG	"pptpd"
77dd7cddfSDavid du Colombier 
87dd7cddfSDavid du Colombier typedef struct Call	Call;
97dd7cddfSDavid du Colombier typedef struct Event Event;
107dd7cddfSDavid du Colombier 
117dd7cddfSDavid du Colombier #define	SDB	if(debug) fprint(2,
127dd7cddfSDavid du Colombier #define EDB	);
137dd7cddfSDavid du Colombier 
147dd7cddfSDavid du Colombier enum {
157dd7cddfSDavid du Colombier 	Magic	= 0x1a2b3c4d,
167dd7cddfSDavid du Colombier 	Nhash	= 17,
177dd7cddfSDavid du Colombier 	Nchan	= 10,		/* maximum number of channels */
187dd7cddfSDavid du Colombier 	Window	= 8,		/* default window size */
197dd7cddfSDavid du Colombier 	Timeout	= 60,		/* timeout in seconds for control channel */
207dd7cddfSDavid du Colombier 	Pktsize = 2000,		/* maximum packet size */
217dd7cddfSDavid du Colombier 	Tick	= 500,		/* tick length in milliseconds */
227dd7cddfSDavid du Colombier 	Sendtimeout = 4,	/* in ticks */
237dd7cddfSDavid du Colombier };
247dd7cddfSDavid du Colombier 
257dd7cddfSDavid du Colombier enum {
267dd7cddfSDavid du Colombier 	Syncframe	= 0x1,
277dd7cddfSDavid du Colombier 	Asyncframe	= 0x2,
287dd7cddfSDavid du Colombier 	Analog		= 0x1,
297dd7cddfSDavid du Colombier 	Digital		= 0x2,
307dd7cddfSDavid du Colombier 	Version		= 0x100,
317dd7cddfSDavid du Colombier };
327dd7cddfSDavid du Colombier 
337dd7cddfSDavid du Colombier enum {
347dd7cddfSDavid du Colombier 	Tstart		= 1,
357dd7cddfSDavid du Colombier 	Rstart		= 2,
367dd7cddfSDavid du Colombier 	Tstop		= 3,
377dd7cddfSDavid du Colombier 	Rstop		= 4,
387dd7cddfSDavid du Colombier 	Techo		= 5,
397dd7cddfSDavid du Colombier 	Recho		= 6,
407dd7cddfSDavid du Colombier 	Tcallout	= 7,
417dd7cddfSDavid du Colombier 	Rcallout	= 8,
427dd7cddfSDavid du Colombier 	Tcallreq	= 9,
437dd7cddfSDavid du Colombier 	Rcallreq	= 10,
447dd7cddfSDavid du Colombier 	Acallcon	= 11,
457dd7cddfSDavid du Colombier 	Tcallclear	= 12,
467dd7cddfSDavid du Colombier 	Acalldis	= 13,
477dd7cddfSDavid du Colombier 	Awaninfo	= 14,
487dd7cddfSDavid du Colombier 	Alinkinfo	= 15,
497dd7cddfSDavid du Colombier };
507dd7cddfSDavid du Colombier 
517dd7cddfSDavid du Colombier 
527dd7cddfSDavid du Colombier struct Event {
537dd7cddfSDavid du Colombier 	QLock;
547dd7cddfSDavid du Colombier 	QLock waitlk;
557dd7cddfSDavid du Colombier 	int	wait;
567dd7cddfSDavid du Colombier 	int ready;
577dd7cddfSDavid du Colombier };
587dd7cddfSDavid du Colombier 
597dd7cddfSDavid du Colombier struct Call {
607dd7cddfSDavid du Colombier 	int	ref;
617dd7cddfSDavid du Colombier 	QLock	lk;
627dd7cddfSDavid du Colombier 	int	id;
637dd7cddfSDavid du Colombier 	int	serial;
647dd7cddfSDavid du Colombier 	int	pppfd;
657dd7cddfSDavid du Colombier 
667dd7cddfSDavid du Colombier 	int	closed;
677dd7cddfSDavid du Colombier 
687dd7cddfSDavid du Colombier 	int	pac;	/* server is acting as a PAC */
697dd7cddfSDavid du Colombier 
707dd7cddfSDavid du Colombier 	int	recvwindow;	/* recv windows */
717dd7cddfSDavid du Colombier 	int	sendwindow;	/* send windows */
727dd7cddfSDavid du Colombier 	int	delay;
737dd7cddfSDavid du Colombier 
747dd7cddfSDavid du Colombier 	int	sendaccm;
757dd7cddfSDavid du Colombier 	int	recvaccm;
767dd7cddfSDavid du Colombier 
777dd7cddfSDavid du Colombier 	uint	seq;		/* current seq number - for send */
787dd7cddfSDavid du Colombier 	uint	ack;		/* current acked mesg - for send */
797dd7cddfSDavid du Colombier 	uint	rseq;		/* highest recv seq number for in order packet  */
807dd7cddfSDavid du Colombier 	uint	rack;		/* highest ack sent */
817dd7cddfSDavid du Colombier 
827dd7cddfSDavid du Colombier 	Event	eack;		/* recved ack - for send */
837dd7cddfSDavid du Colombier 	ulong	tick;
847dd7cddfSDavid du Colombier 
857dd7cddfSDavid du Colombier 	uchar	remoteip[IPaddrlen];	/* remote ip address */
867dd7cddfSDavid du Colombier 	int	dhcpfd[2];	/* pipe to dhcpclient */
877dd7cddfSDavid du Colombier 
887dd7cddfSDavid du Colombier 	/* error stats */
897dd7cddfSDavid du Colombier 	struct {
907dd7cddfSDavid du Colombier 		int	crc;
917dd7cddfSDavid du Colombier 		int	frame;
927dd7cddfSDavid du Colombier 		int	hardware;
937dd7cddfSDavid du Colombier 		int	overrun;
947dd7cddfSDavid du Colombier 		int	timeout;
957dd7cddfSDavid du Colombier 		int	align;
967dd7cddfSDavid du Colombier 	} err;
977dd7cddfSDavid du Colombier 
987dd7cddfSDavid du Colombier 	struct {
997dd7cddfSDavid du Colombier 		int	send;
1007dd7cddfSDavid du Colombier 		int	sendack;
1017dd7cddfSDavid du Colombier 		int	recv;
1027dd7cddfSDavid du Colombier 		int	recvack;
1037dd7cddfSDavid du Colombier 		int	dropped;
1047dd7cddfSDavid du Colombier 		int	missing;
1057dd7cddfSDavid du Colombier 		int	sendwait;
1067dd7cddfSDavid du Colombier 		int	sendtimeout;
1077dd7cddfSDavid du Colombier 	} stat;
1087dd7cddfSDavid du Colombier 
1097dd7cddfSDavid du Colombier 	Call	*next;
1107dd7cddfSDavid du Colombier };
1117dd7cddfSDavid du Colombier 
1127dd7cddfSDavid du Colombier struct {
1137dd7cddfSDavid du Colombier 	QLock	lk;
1147dd7cddfSDavid du Colombier 	int	start;
1157dd7cddfSDavid du Colombier 	int	grefd;
1167dd7cddfSDavid du Colombier 	int	grecfd;
1177dd7cddfSDavid du Colombier 	uchar	local[IPaddrlen];
1187dd7cddfSDavid du Colombier 	uchar	remote[IPaddrlen];
1197dd7cddfSDavid du Colombier 	char	*tcpdir;
1207dd7cddfSDavid du Colombier 	uchar	ipaddr[IPaddrlen];		/* starting ip addresss to allocate */
1217dd7cddfSDavid du Colombier 
1227dd7cddfSDavid du Colombier 	int	recvwindow;
1237dd7cddfSDavid du Colombier 
1247dd7cddfSDavid du Colombier 	char	*pppdir;
12580ee5cbfSDavid du Colombier 	char	*pppexec;
1267dd7cddfSDavid du Colombier 
1277dd7cddfSDavid du Colombier 	double	rcvtime;	/* time at which last request was received */
1287dd7cddfSDavid du Colombier 	int	echoid;		/* id of last echo request */
1297dd7cddfSDavid du Colombier 
1307dd7cddfSDavid du Colombier 	Call	*hash[Nhash];
1317dd7cddfSDavid du Colombier } srv;
1327dd7cddfSDavid du Colombier 
1337dd7cddfSDavid du Colombier /* GRE flag bits */
1347dd7cddfSDavid du Colombier enum {
1357dd7cddfSDavid du Colombier 	GRE_chksum	= (1<<15),
1367dd7cddfSDavid du Colombier 	GRE_routing	= (1<<14),
1377dd7cddfSDavid du Colombier 	GRE_key		= (1<<13),
1387dd7cddfSDavid du Colombier 	GRE_seq		= (1<<12),
1397dd7cddfSDavid du Colombier 	GRE_srcrt	= (1<<11),
1407dd7cddfSDavid du Colombier 	GRE_recur	= (7<<8),
1417dd7cddfSDavid du Colombier 	GRE_ack		= (1<<7),
1427dd7cddfSDavid du Colombier 	GRE_ver		= 0x7,
1437dd7cddfSDavid du Colombier };
1447dd7cddfSDavid du Colombier 
1457dd7cddfSDavid du Colombier /* GRE protocols */
1467dd7cddfSDavid du Colombier enum {
1477dd7cddfSDavid du Colombier 	GRE_ppp		= 0x880b,
1487dd7cddfSDavid du Colombier };
1497dd7cddfSDavid du Colombier 
1507dd7cddfSDavid du Colombier int	debug;
1517dd7cddfSDavid du Colombier double	drop;
1527dd7cddfSDavid du Colombier 
1537dd7cddfSDavid du Colombier void	myfatal(char *fmt, ...);
1547dd7cddfSDavid du Colombier 
1557dd7cddfSDavid du Colombier #define	PSHORT(p, v)		((p)[0]=((v)>>8), (p)[1]=(v))
1567dd7cddfSDavid du Colombier #define	PLONG(p, v)		(PSHORT(p, (v)>>16), PSHORT(p+2, (v)))
1577dd7cddfSDavid du Colombier #define	PSTRING(d,s,n)		strncpy((char*)(d), s, n)
1587dd7cddfSDavid du Colombier #define	GSHORT(p)		(((p)[0]<<8) | ((p)[1]<<0))
1597dd7cddfSDavid du Colombier #define	GLONG(p)		((GSHORT((p))<<16) | ((GSHORT((p)+2))<<0))
1607dd7cddfSDavid du Colombier #define	GSTRING(d,s,n)		strncpy(d, (char*)(s), n), d[(n)-1] = 0
1617dd7cddfSDavid du Colombier 
1627dd7cddfSDavid du Colombier void	serve(void);
1637dd7cddfSDavid du Colombier 
1647dd7cddfSDavid du Colombier int	sstart(uchar*, int);
1657dd7cddfSDavid du Colombier int	sstop(uchar*, int);
1667dd7cddfSDavid du Colombier int	secho(uchar*, int);
1677dd7cddfSDavid du Colombier int	scallout(uchar*, int);
1687dd7cddfSDavid du Colombier int	scallreq(uchar*, int);
1697dd7cddfSDavid du Colombier int	scallcon(uchar*, int);
1707dd7cddfSDavid du Colombier int	scallclear(uchar*, int);
1717dd7cddfSDavid du Colombier int	scalldis(uchar*, int);
1727dd7cddfSDavid du Colombier int	swaninfo(uchar*, int);
1737dd7cddfSDavid du Colombier int	slinkinfo(uchar*, int);
1747dd7cddfSDavid du Colombier 
1757dd7cddfSDavid du Colombier Call	*callalloc(int id);
1767dd7cddfSDavid du Colombier void	callclose(Call*);
1777dd7cddfSDavid du Colombier void	callfree(Call*);
1787dd7cddfSDavid du Colombier Call	*calllookup(int id);
1797dd7cddfSDavid du Colombier 
1807dd7cddfSDavid du Colombier void	gretimeout(void*);
1817dd7cddfSDavid du Colombier void	pppread(void*);
1827dd7cddfSDavid du Colombier 
1837dd7cddfSDavid du Colombier void	srvinit(void);
1847dd7cddfSDavid du Colombier void	greinit(void);
1857dd7cddfSDavid du Colombier void	greread(void*);
1867dd7cddfSDavid du Colombier void	greack(Call *c);
1877dd7cddfSDavid du Colombier 
1887dd7cddfSDavid du Colombier void	timeoutthread(void*);
1897dd7cddfSDavid du Colombier 
1907dd7cddfSDavid du Colombier int	argatoi(char *p);
1917dd7cddfSDavid du Colombier void	usage(void);
1927dd7cddfSDavid du Colombier int	ipaddralloc(Call *c);
1937dd7cddfSDavid du Colombier 
194*ea58ad6fSDavid du Colombier void	*emallocz(int size);
1957dd7cddfSDavid du Colombier void	esignal(Event *e);
1967dd7cddfSDavid du Colombier void	ewait(Event *e);
1977dd7cddfSDavid du Colombier int	proc(char **argv, int fd0, int fd1, int fd2);
198*ea58ad6fSDavid du Colombier double	realtime(void);
199*ea58ad6fSDavid du Colombier ulong	thread(void(*f)(void*), void *a);
2007dd7cddfSDavid du Colombier 
2017dd7cddfSDavid du Colombier void
main(int argc,char * argv[])2027dd7cddfSDavid du Colombier main(int argc, char *argv[])
2037dd7cddfSDavid du Colombier {
2047dd7cddfSDavid du Colombier 	ARGBEGIN{
2057dd7cddfSDavid du Colombier 	case 'd': debug++; break;
2067dd7cddfSDavid du Colombier 	case 'p': srv.pppdir = ARGF(); break;
20780ee5cbfSDavid du Colombier 	case 'P': srv.pppexec = ARGF(); break;
2087dd7cddfSDavid du Colombier 	case 'w': srv.recvwindow = argatoi(ARGF()); break;
2097dd7cddfSDavid du Colombier 	case 'D': drop = atof(ARGF()); break;
2107dd7cddfSDavid du Colombier 	default:
2117dd7cddfSDavid du Colombier 		usage();
2127dd7cddfSDavid du Colombier 	}ARGEND
2137dd7cddfSDavid du Colombier 
2149a747e4fSDavid du Colombier 	fmtinstall('I', eipfmt);
2159a747e4fSDavid du Colombier 	fmtinstall('E', eipfmt);
2169a747e4fSDavid du Colombier 	fmtinstall('V', eipfmt);
2179a747e4fSDavid du Colombier 	fmtinstall('M', eipfmt);
2187dd7cddfSDavid du Colombier 
2197dd7cddfSDavid du Colombier 	rfork(RFNOTEG|RFREND);
2207dd7cddfSDavid du Colombier 
2217dd7cddfSDavid du Colombier 	if(argc != 1)
2227dd7cddfSDavid du Colombier 		usage();
2237dd7cddfSDavid du Colombier 
2247dd7cddfSDavid du Colombier 	srv.tcpdir = argv[0];
2257dd7cddfSDavid du Colombier 
2267dd7cddfSDavid du Colombier 	srvinit();
2277dd7cddfSDavid du Colombier 
2287dd7cddfSDavid du Colombier 	syslog(0, LOG, ": src=%I: pptp started: %d", srv.remote, getpid());
2297dd7cddfSDavid du Colombier 
2307dd7cddfSDavid du Colombier 	SDB  "\n\n\n%I: pptp started\n", srv.remote EDB
2317dd7cddfSDavid du Colombier 
2327dd7cddfSDavid du Colombier 	greinit();
2337dd7cddfSDavid du Colombier 
2347dd7cddfSDavid du Colombier 	thread(timeoutthread, 0);
2357dd7cddfSDavid du Colombier 
2367dd7cddfSDavid du Colombier 	serve();
2377dd7cddfSDavid du Colombier 
2387dd7cddfSDavid du Colombier 	syslog(0, LOG, ": src=%I: server exits", srv.remote);
2397dd7cddfSDavid du Colombier 
2407dd7cddfSDavid du Colombier 	exits(0);
2417dd7cddfSDavid du Colombier }
2427dd7cddfSDavid du Colombier 
2437dd7cddfSDavid du Colombier void
usage(void)2447dd7cddfSDavid du Colombier usage(void)
2457dd7cddfSDavid du Colombier {
24659cc4ca5SDavid du Colombier 	fprint(2, "usage: pptpd [-dD] [-p ppp-net] [-w window] tcpdir\n");
2477dd7cddfSDavid du Colombier 	exits("usage");
2487dd7cddfSDavid du Colombier }
2497dd7cddfSDavid du Colombier 
2507dd7cddfSDavid du Colombier void
serve(void)2517dd7cddfSDavid du Colombier serve(void)
2527dd7cddfSDavid du Colombier {
2537dd7cddfSDavid du Colombier 	uchar buf[2000], *p;
2547dd7cddfSDavid du Colombier 	int n, n2, len;
2557dd7cddfSDavid du Colombier 	int magic;
2567dd7cddfSDavid du Colombier 	int op, type;
2577dd7cddfSDavid du Colombier 
2587dd7cddfSDavid du Colombier 	n = 0;
2597dd7cddfSDavid du Colombier 	for(;;) {
2607dd7cddfSDavid du Colombier 		n2 = read(0, buf+n, sizeof(buf)-n);
2617dd7cddfSDavid du Colombier 		if(n2 < 0)
2627dd7cddfSDavid du Colombier 			myfatal("bad read on ctl channel: %r");
2637dd7cddfSDavid du Colombier 		if(n2 == 0)
2647dd7cddfSDavid du Colombier 			break;
2657dd7cddfSDavid du Colombier 		n += n2;
2667dd7cddfSDavid du Colombier 		p = buf;
2677dd7cddfSDavid du Colombier 		for(;;) {
2687dd7cddfSDavid du Colombier 			if(n < 12)
2697dd7cddfSDavid du Colombier 				break;
2707dd7cddfSDavid du Colombier 
2717dd7cddfSDavid du Colombier 			qlock(&srv.lk);
2727dd7cddfSDavid du Colombier 			srv.rcvtime = realtime();
2737dd7cddfSDavid du Colombier 			qunlock(&srv.lk);
2747dd7cddfSDavid du Colombier 
2757dd7cddfSDavid du Colombier 			len = GSHORT(p);
2767dd7cddfSDavid du Colombier 			type = GSHORT(p+2);
2777dd7cddfSDavid du Colombier 			magic = GLONG(p+4);
2787dd7cddfSDavid du Colombier 			op = GSHORT(p+8);
2797dd7cddfSDavid du Colombier 			if(magic != Magic)
2807dd7cddfSDavid du Colombier 				myfatal("bad magic number: got %x", magic);
2817dd7cddfSDavid du Colombier 			if(type != 1)
2827dd7cddfSDavid du Colombier 				myfatal("bad message type: %d", type);
2837dd7cddfSDavid du Colombier 			switch(op) {
2847dd7cddfSDavid du Colombier 			default:
2857dd7cddfSDavid du Colombier 				myfatal("unknown control op: %d", op);
2867dd7cddfSDavid du Colombier 			case Tstart:		/* start-control-connection-request */
2877dd7cddfSDavid du Colombier 				n2 = sstart(p, n);
2887dd7cddfSDavid du Colombier 				break;
2897dd7cddfSDavid du Colombier 			case Tstop:
2907dd7cddfSDavid du Colombier 				n2 = sstop(p, n);
2917dd7cddfSDavid du Colombier 				if(n2 > 0)
2927dd7cddfSDavid du Colombier 					return;
2937dd7cddfSDavid du Colombier 				break;
2947dd7cddfSDavid du Colombier 			case Techo:
2957dd7cddfSDavid du Colombier 				n2 = secho(p, n);
2967dd7cddfSDavid du Colombier 				break;
2977dd7cddfSDavid du Colombier 			case Tcallout:
2987dd7cddfSDavid du Colombier 				n2 = scallout(p, n);
2997dd7cddfSDavid du Colombier 				break;
3007dd7cddfSDavid du Colombier 			case Tcallreq:
3017dd7cddfSDavid du Colombier 				n2 = scallreq(p, n);
3027dd7cddfSDavid du Colombier 				break;
3037dd7cddfSDavid du Colombier 			case Acallcon:
3047dd7cddfSDavid du Colombier 				n2 = scallcon(p, n);
3057dd7cddfSDavid du Colombier 				break;
3067dd7cddfSDavid du Colombier 			case Tcallclear:
3077dd7cddfSDavid du Colombier 				n2 = scallclear(p, n);
3087dd7cddfSDavid du Colombier 				break;
3097dd7cddfSDavid du Colombier 			case Acalldis:
3107dd7cddfSDavid du Colombier 				n2 = scalldis(p, n);
3117dd7cddfSDavid du Colombier 				break;
3127dd7cddfSDavid du Colombier 			case Awaninfo:
3137dd7cddfSDavid du Colombier 				n2 = swaninfo(p, n);
3147dd7cddfSDavid du Colombier 				break;
3157dd7cddfSDavid du Colombier 			case Alinkinfo:
3167dd7cddfSDavid du Colombier 				n2 = slinkinfo(p, n);
3177dd7cddfSDavid du Colombier 				break;
3187dd7cddfSDavid du Colombier 			}
3197dd7cddfSDavid du Colombier 			if(n2 == 0)
3207dd7cddfSDavid du Colombier 				break;
3217dd7cddfSDavid du Colombier 			if(n2 != len)
3227dd7cddfSDavid du Colombier 				myfatal("op=%d: bad length: got %d expected %d", op, len, n2);
3237dd7cddfSDavid du Colombier 			n -= n2;
3247dd7cddfSDavid du Colombier 			p += n2;
3257dd7cddfSDavid du Colombier 
3267dd7cddfSDavid du Colombier 		}
3277dd7cddfSDavid du Colombier 
3287dd7cddfSDavid du Colombier 		/* move down partial message */
3297dd7cddfSDavid du Colombier 		if(p != buf && n != 0)
3307dd7cddfSDavid du Colombier 			memmove(buf, p, n);
3317dd7cddfSDavid du Colombier 	}
3327dd7cddfSDavid du Colombier 
3337dd7cddfSDavid du Colombier }
3347dd7cddfSDavid du Colombier 
3357dd7cddfSDavid du Colombier int
sstart(uchar * p,int n)3367dd7cddfSDavid du Colombier sstart(uchar *p, int n)
3377dd7cddfSDavid du Colombier {
3387dd7cddfSDavid du Colombier 	int ver, frame, bearer, maxchan, firm;
3397dd7cddfSDavid du Colombier 	char host[64], vendor[64], *sysname;
3407dd7cddfSDavid du Colombier 	uchar buf[156];
3417dd7cddfSDavid du Colombier 
3427dd7cddfSDavid du Colombier 	if(n < 156)
3437dd7cddfSDavid du Colombier 		return 0;
3447dd7cddfSDavid du Colombier 	ver = GSHORT(p+12);
3457dd7cddfSDavid du Colombier 	frame = GLONG(p+16);
3467dd7cddfSDavid du Colombier 	bearer = GLONG(p+20);
3477dd7cddfSDavid du Colombier 	maxchan = GSHORT(p+24);
3487dd7cddfSDavid du Colombier 	firm = GSHORT(p+26);
3497dd7cddfSDavid du Colombier 	GSTRING(host, p+28, 64);
3507dd7cddfSDavid du Colombier 	GSTRING(vendor, p+92, 64);
3517dd7cddfSDavid du Colombier 
3527dd7cddfSDavid du Colombier 	SDB "%I: start ver = %x f = %d b = %d maxchan = %d firm = %d host = %s vendor = %s\n",
3537dd7cddfSDavid du Colombier 		srv.remote, ver, frame, bearer, maxchan, firm, host, vendor EDB
3547dd7cddfSDavid du Colombier 
3557dd7cddfSDavid du Colombier 	if(ver != Version)
3567dd7cddfSDavid du Colombier 		myfatal("bad version: got %x expected %x", ver, Version);
3577dd7cddfSDavid du Colombier 
3587dd7cddfSDavid du Colombier 	if(srv.start)
3597dd7cddfSDavid du Colombier 		myfatal("multiple start messages");
3607dd7cddfSDavid du Colombier 
3617dd7cddfSDavid du Colombier 	srv.start = 1;
3627dd7cddfSDavid du Colombier 
3637dd7cddfSDavid du Colombier 	sysname = getenv("sysname");
3647dd7cddfSDavid du Colombier 	if(sysname == 0)
3657dd7cddfSDavid du Colombier 		strcpy(host, "gnot");
3667dd7cddfSDavid du Colombier 	else
3677dd7cddfSDavid du Colombier 		strncpy(host, sysname, 64);
3687dd7cddfSDavid du Colombier 	free(sysname);
3697dd7cddfSDavid du Colombier 
3707dd7cddfSDavid du Colombier 	memset(buf, 0, sizeof(buf));
3717dd7cddfSDavid du Colombier 
3727dd7cddfSDavid du Colombier 	PSHORT(buf+0, sizeof(buf));	/* length */
3737dd7cddfSDavid du Colombier 	PSHORT(buf+2, 1);		/* message type */
3747dd7cddfSDavid du Colombier 	PLONG(buf+4, Magic);		/* magic */
3757dd7cddfSDavid du Colombier 	PSHORT(buf+8, Rstart);		/* op */
3767dd7cddfSDavid du Colombier 	PSHORT(buf+12, Version);	/* version */
3777dd7cddfSDavid du Colombier 	buf[14] = 1;			/* result = ok */
3787dd7cddfSDavid du Colombier 	PLONG(buf+16, Syncframe|Asyncframe);	/* frameing */
3797dd7cddfSDavid du Colombier 	PLONG(buf+20, Digital|Analog);	/* berear capabilities */
3807dd7cddfSDavid du Colombier 	PSHORT(buf+24, Nchan);		/* max channels */
3817dd7cddfSDavid du Colombier 	PSHORT(buf+26, 1);		/* driver version */
3827dd7cddfSDavid du Colombier 	PSTRING(buf+28, host, 64);	/* host name */
3837dd7cddfSDavid du Colombier 	PSTRING(buf+92, "plan 9", 64);	/* vendor */
3847dd7cddfSDavid du Colombier 
3857dd7cddfSDavid du Colombier 	if(write(1, buf, sizeof(buf)) < sizeof(buf))
3867dd7cddfSDavid du Colombier 		myfatal("write failed: %r");
3877dd7cddfSDavid du Colombier 
3887dd7cddfSDavid du Colombier 	return 156;
3897dd7cddfSDavid du Colombier }
3907dd7cddfSDavid du Colombier 
3917dd7cddfSDavid du Colombier int
sstop(uchar * p,int n)3927dd7cddfSDavid du Colombier sstop(uchar *p, int n)
3937dd7cddfSDavid du Colombier {
3947dd7cddfSDavid du Colombier 	int reason;
3957dd7cddfSDavid du Colombier 	uchar buf[16];
3967dd7cddfSDavid du Colombier 
3977dd7cddfSDavid du Colombier 	if(n < 16)
3987dd7cddfSDavid du Colombier 		return 0;
3997dd7cddfSDavid du Colombier 	reason = p[12];
4007dd7cddfSDavid du Colombier 
4017dd7cddfSDavid du Colombier 	SDB "%I: stop %d\n", srv.remote, reason EDB
4027dd7cddfSDavid du Colombier 
4037dd7cddfSDavid du Colombier 	memset(buf, 0, sizeof(buf));
4047dd7cddfSDavid du Colombier 	PSHORT(buf+0, sizeof(buf));	/* length */
4057dd7cddfSDavid du Colombier 	PSHORT(buf+2, 1);		/* message type */
4067dd7cddfSDavid du Colombier 	PLONG(buf+4, Magic);		/* magic */
4077dd7cddfSDavid du Colombier 	PSHORT(buf+8, Rstop);		/* op */
4087dd7cddfSDavid du Colombier 	buf[12] = 1;			/* ok */
4097dd7cddfSDavid du Colombier 
4107dd7cddfSDavid du Colombier 	if(write(1, buf, sizeof(buf)) < sizeof(buf))
4117dd7cddfSDavid du Colombier 		myfatal("write failed: %r");
4127dd7cddfSDavid du Colombier 
4137dd7cddfSDavid du Colombier 	return 16;
4147dd7cddfSDavid du Colombier }
4157dd7cddfSDavid du Colombier 
4167dd7cddfSDavid du Colombier int
secho(uchar * p,int n)4177dd7cddfSDavid du Colombier secho(uchar *p, int n)
4187dd7cddfSDavid du Colombier {
4197dd7cddfSDavid du Colombier 	int id;
4207dd7cddfSDavid du Colombier 	uchar buf[20];
4217dd7cddfSDavid du Colombier 
4227dd7cddfSDavid du Colombier 	if(n < 16)
4237dd7cddfSDavid du Colombier 		return 0;
4247dd7cddfSDavid du Colombier 	id = GLONG(p+12);
4257dd7cddfSDavid du Colombier 
4267dd7cddfSDavid du Colombier 	SDB "%I: echo %d\n", srv.remote, id EDB
4277dd7cddfSDavid du Colombier 
4287dd7cddfSDavid du Colombier 	memset(buf, 0, sizeof(buf));
4297dd7cddfSDavid du Colombier 	PSHORT(buf+0, sizeof(buf));	/* length */
4307dd7cddfSDavid du Colombier 	PSHORT(buf+2, 1);		/* message type */
4317dd7cddfSDavid du Colombier 	PLONG(buf+4, Magic);		/* magic */
4327dd7cddfSDavid du Colombier 	PSHORT(buf+8, Recho);		/* op */
4337dd7cddfSDavid du Colombier 	PLONG(buf+12, id);		/* id */
4347dd7cddfSDavid du Colombier 	p[16] = 1;			/* ok */
4357dd7cddfSDavid du Colombier 
4367dd7cddfSDavid du Colombier 	if(write(1, buf, sizeof(buf)) < sizeof(buf))
4377dd7cddfSDavid du Colombier 		myfatal("write failed: %r");
4387dd7cddfSDavid du Colombier 
4397dd7cddfSDavid du Colombier 	return 16;
4407dd7cddfSDavid du Colombier }
4417dd7cddfSDavid du Colombier 
4427dd7cddfSDavid du Colombier int
scallout(uchar * p,int n)4437dd7cddfSDavid du Colombier scallout(uchar *p, int n)
4447dd7cddfSDavid du Colombier {
4457dd7cddfSDavid du Colombier 	int id, serial;
4467dd7cddfSDavid du Colombier 	int minbps, maxbps, bearer, frame;
4477dd7cddfSDavid du Colombier 	int window, delay;
4487dd7cddfSDavid du Colombier 	int nphone;
4497dd7cddfSDavid du Colombier 	char phone[64], sub[64], buf[32];
4507dd7cddfSDavid du Colombier 	Call *c;
4517dd7cddfSDavid du Colombier 
4527dd7cddfSDavid du Colombier 	if(n < 168)
4537dd7cddfSDavid du Colombier 		return 0;
4547dd7cddfSDavid du Colombier 
4557dd7cddfSDavid du Colombier 	if(!srv.start)
4567dd7cddfSDavid du Colombier 		myfatal("%I: did not recieve start message", srv.remote);
4577dd7cddfSDavid du Colombier 
4587dd7cddfSDavid du Colombier 	id = GSHORT(p+12);
4597dd7cddfSDavid du Colombier 	serial = GSHORT(p+14);
4607dd7cddfSDavid du Colombier 	minbps = GLONG(p+16);
4617dd7cddfSDavid du Colombier 	maxbps = GLONG(p+20);
4627dd7cddfSDavid du Colombier 	bearer = GLONG(p+24);
4637dd7cddfSDavid du Colombier 	frame = GLONG(p+28);
4647dd7cddfSDavid du Colombier 	window = GSHORT(p+32);
4657dd7cddfSDavid du Colombier 	delay = GSHORT(p+34);
4667dd7cddfSDavid du Colombier 	nphone = GSHORT(p+36);
4677dd7cddfSDavid du Colombier 	GSTRING(phone, p+40, 64);
4687dd7cddfSDavid du Colombier 	GSTRING(sub, p+104, 64);
4697dd7cddfSDavid du Colombier 
4707dd7cddfSDavid du Colombier 	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",
4717dd7cddfSDavid du Colombier 		srv.remote, id, serial, minbps, maxbps, bearer, frame, window, delay, nphone, phone, sub EDB
4727dd7cddfSDavid du Colombier 
4737dd7cddfSDavid du Colombier 	c = callalloc(id);
4747dd7cddfSDavid du Colombier 	c->sendwindow = window;
4757dd7cddfSDavid du Colombier 	c->delay = delay;
4767dd7cddfSDavid du Colombier 	c->pac = 1;
4777dd7cddfSDavid du Colombier 	c->recvwindow = srv.recvwindow;
4787dd7cddfSDavid du Colombier 
4797dd7cddfSDavid du Colombier 	memset(buf, 0, sizeof(buf));
4807dd7cddfSDavid du Colombier 	PSHORT(buf+0, sizeof(buf));	/* length */
4817dd7cddfSDavid du Colombier 	PSHORT(buf+2, 1);		/* message type */
4827dd7cddfSDavid du Colombier 	PLONG(buf+4, Magic);		/* magic */
4837dd7cddfSDavid du Colombier 	PSHORT(buf+8, Rcallout);	/* op */
4847dd7cddfSDavid du Colombier 	PSHORT(buf+12, id);		/* call id */
4857dd7cddfSDavid du Colombier 	PSHORT(buf+14, id);		/* peer id */
4867dd7cddfSDavid du Colombier 	buf[16] = 1;			/* ok */
4877dd7cddfSDavid du Colombier 	PLONG(buf+20, 10000000);	/* speed */
4887dd7cddfSDavid du Colombier 	PSHORT(buf+24, c->recvwindow);	/* window size */
4897dd7cddfSDavid du Colombier 	PSHORT(buf+26, 0);		/* delay */
4907dd7cddfSDavid du Colombier 	PLONG(buf+28, 0);		/* channel id */
4917dd7cddfSDavid du Colombier 
4927dd7cddfSDavid du Colombier 	if(write(1, buf, sizeof(buf)) < sizeof(buf))
4937dd7cddfSDavid du Colombier 		myfatal("write failed: %r");
4947dd7cddfSDavid du Colombier 
4957dd7cddfSDavid du Colombier 	return 168;
4967dd7cddfSDavid du Colombier }
4977dd7cddfSDavid du Colombier 
4987dd7cddfSDavid du Colombier int
scallreq(uchar * p,int n)4997dd7cddfSDavid du Colombier scallreq(uchar *p, int n)
5007dd7cddfSDavid du Colombier {
5017dd7cddfSDavid du Colombier 	USED(p);
5027dd7cddfSDavid du Colombier 	USED(n);
5037dd7cddfSDavid du Colombier 
5047dd7cddfSDavid du Colombier 	myfatal("callreq: not done yet");
5057dd7cddfSDavid du Colombier 	return 0;
5067dd7cddfSDavid du Colombier }
5077dd7cddfSDavid du Colombier 
5087dd7cddfSDavid du Colombier int
scallcon(uchar * p,int n)5097dd7cddfSDavid du Colombier scallcon(uchar *p, int n)
5107dd7cddfSDavid du Colombier {
5117dd7cddfSDavid du Colombier 	USED(p);
5127dd7cddfSDavid du Colombier 	USED(n);
5137dd7cddfSDavid du Colombier 
5147dd7cddfSDavid du Colombier 	myfatal("callcon: not done yet");
5157dd7cddfSDavid du Colombier 	return 0;
5167dd7cddfSDavid du Colombier }
5177dd7cddfSDavid du Colombier 
5187dd7cddfSDavid du Colombier int
scallclear(uchar * p,int n)5197dd7cddfSDavid du Colombier scallclear(uchar *p, int n)
5207dd7cddfSDavid du Colombier {
5217dd7cddfSDavid du Colombier 	Call *c;
5227dd7cddfSDavid du Colombier 	int id;
5237dd7cddfSDavid du Colombier 	uchar buf[148];
5247dd7cddfSDavid du Colombier 
5257dd7cddfSDavid du Colombier 	if(n < 16)
5267dd7cddfSDavid du Colombier 		return 0;
5277dd7cddfSDavid du Colombier 	id = GSHORT(p+12);
5287dd7cddfSDavid du Colombier 
5297dd7cddfSDavid du Colombier 	SDB "%I: callclear id=%d\n", srv.remote, id EDB
5307dd7cddfSDavid du Colombier 
5317dd7cddfSDavid du Colombier 	if(c = calllookup(id)) {
5327dd7cddfSDavid du Colombier 		callclose(c);
5337dd7cddfSDavid du Colombier 		callfree(c);
5347dd7cddfSDavid du Colombier 	}
5357dd7cddfSDavid du Colombier 
5367dd7cddfSDavid du Colombier 	memset(buf, 0, sizeof(buf));
5377dd7cddfSDavid du Colombier 	PSHORT(buf+0, sizeof(buf));	/* length */
5387dd7cddfSDavid du Colombier 	PSHORT(buf+2, 1);		/* message type */
5397dd7cddfSDavid du Colombier 	PLONG(buf+4, Magic);		/* magic */
5407dd7cddfSDavid du Colombier 	PSHORT(buf+8, Acalldis);	/* op */
5417dd7cddfSDavid du Colombier 	PSHORT(buf+12, id);		/* id */
5427dd7cddfSDavid du Colombier 	buf[14] = 3;			/* reply to callclear */
5437dd7cddfSDavid du Colombier 
5447dd7cddfSDavid du Colombier 	if(write(1, buf, sizeof(buf)) < sizeof(buf))
5457dd7cddfSDavid du Colombier 		myfatal("write failed: %r");
5467dd7cddfSDavid du Colombier 
5477dd7cddfSDavid du Colombier 	return 16;
5487dd7cddfSDavid du Colombier }
5497dd7cddfSDavid du Colombier 
5507dd7cddfSDavid du Colombier int
scalldis(uchar * p,int n)5517dd7cddfSDavid du Colombier scalldis(uchar *p, int n)
5527dd7cddfSDavid du Colombier {
5537dd7cddfSDavid du Colombier 	Call *c;
5547dd7cddfSDavid du Colombier 	int id, res;
5557dd7cddfSDavid du Colombier 
5567dd7cddfSDavid du Colombier 	if(n < 148)
5577dd7cddfSDavid du Colombier 		return 0;
5587dd7cddfSDavid du Colombier 	id = GSHORT(p+12);
5597dd7cddfSDavid du Colombier 	res = p[14];
5607dd7cddfSDavid du Colombier 
5617dd7cddfSDavid du Colombier 	SDB "%I: calldis id=%d res=%d\n", srv.remote, id, res EDB
5627dd7cddfSDavid du Colombier 
5637dd7cddfSDavid du Colombier 	if(c = calllookup(id)) {
5647dd7cddfSDavid du Colombier 		callclose(c);
5657dd7cddfSDavid du Colombier 		callfree(c);
5667dd7cddfSDavid du Colombier 	}
5677dd7cddfSDavid du Colombier 
5687dd7cddfSDavid du Colombier 	return 148;
5697dd7cddfSDavid du Colombier }
5707dd7cddfSDavid du Colombier 
5717dd7cddfSDavid du Colombier int
swaninfo(uchar * p,int n)5727dd7cddfSDavid du Colombier swaninfo(uchar *p, int n)
5737dd7cddfSDavid du Colombier {
5747dd7cddfSDavid du Colombier 	Call *c;
5757dd7cddfSDavid du Colombier 	int id;
5767dd7cddfSDavid du Colombier 
5777dd7cddfSDavid du Colombier 	if(n < 40)
5787dd7cddfSDavid du Colombier 		return 0;
5797dd7cddfSDavid du Colombier 
5807dd7cddfSDavid du Colombier 	id = GSHORT(p+12);
5817dd7cddfSDavid du Colombier 	SDB "%I: waninfo id = %d\n", srv.remote, id EDB
5827dd7cddfSDavid du Colombier 
5837dd7cddfSDavid du Colombier 	c = calllookup(id);
5847dd7cddfSDavid du Colombier 	if(c != 0) {
5857dd7cddfSDavid du Colombier 		c->err.crc = GLONG(p+16);
5867dd7cddfSDavid du Colombier 		c->err.frame = GLONG(p+20);
5877dd7cddfSDavid du Colombier 		c->err.hardware = GLONG(p+24);
5887dd7cddfSDavid du Colombier 		c->err.overrun = GLONG(p+28);
5897dd7cddfSDavid du Colombier 		c->err.timeout = GLONG(p+32);
5907dd7cddfSDavid du Colombier 		c->err.align = GLONG(p+36);
5917dd7cddfSDavid du Colombier 
5927dd7cddfSDavid du Colombier 		callfree(c);
5937dd7cddfSDavid du Colombier 	}
5947dd7cddfSDavid du Colombier 
5957dd7cddfSDavid du Colombier 
5967dd7cddfSDavid du Colombier 	return 40;
5977dd7cddfSDavid du Colombier }
5987dd7cddfSDavid du Colombier 
5997dd7cddfSDavid du Colombier int
slinkinfo(uchar * p,int n)6007dd7cddfSDavid du Colombier slinkinfo(uchar *p, int n)
6017dd7cddfSDavid du Colombier {
6027dd7cddfSDavid du Colombier 	Call *c;
6037dd7cddfSDavid du Colombier 	int id;
6047dd7cddfSDavid du Colombier 	int sendaccm, recvaccm;
6057dd7cddfSDavid du Colombier 
6067dd7cddfSDavid du Colombier 	if(n < 24)
6077dd7cddfSDavid du Colombier 		return 0;
6087dd7cddfSDavid du Colombier 	id = GSHORT(p+12);
6097dd7cddfSDavid du Colombier 	sendaccm = GLONG(p+16);
6107dd7cddfSDavid du Colombier 	recvaccm = GLONG(p+20);
6117dd7cddfSDavid du Colombier 
6127dd7cddfSDavid du Colombier 	SDB "%I: linkinfo id=%d saccm=%ux raccm=%ux\n", srv.remote, id, sendaccm, recvaccm EDB
6137dd7cddfSDavid du Colombier 
6147dd7cddfSDavid du Colombier 	if(c = calllookup(id)) {
6157dd7cddfSDavid du Colombier 		c->sendaccm = sendaccm;
6167dd7cddfSDavid du Colombier 		c->recvaccm = recvaccm;
6177dd7cddfSDavid du Colombier 
6187dd7cddfSDavid du Colombier 		callfree(c);
6197dd7cddfSDavid du Colombier 	}
6207dd7cddfSDavid du Colombier 
6217dd7cddfSDavid du Colombier 	return 24;
6227dd7cddfSDavid du Colombier }
6237dd7cddfSDavid du Colombier 
6247dd7cddfSDavid du Colombier Call*
callalloc(int id)6257dd7cddfSDavid du Colombier callalloc(int id)
6267dd7cddfSDavid du Colombier {
6277dd7cddfSDavid du Colombier 	uint h;
6287dd7cddfSDavid du Colombier 	Call *c;
6297dd7cddfSDavid du Colombier 	char buf[300], *argv[30], local[20], remote[20], **p;
6307dd7cddfSDavid du Colombier 	int fd, pfd[2], n;
6317dd7cddfSDavid du Colombier 
6327dd7cddfSDavid du Colombier 	h = id%Nhash;
6337dd7cddfSDavid du Colombier 
6347dd7cddfSDavid du Colombier 	qlock(&srv.lk);
6357dd7cddfSDavid du Colombier 	for(c=srv.hash[h]; c; c=c->next)
6367dd7cddfSDavid du Colombier 		if(c->id == id)
6377dd7cddfSDavid du Colombier 			myfatal("callalloc: duplicate id: %d", id);
6387dd7cddfSDavid du Colombier 	c = emallocz(sizeof(Call));
6397dd7cddfSDavid du Colombier 	c->ref = 1;
6407dd7cddfSDavid du Colombier 	c->id = id;
6417dd7cddfSDavid du Colombier 	c->sendaccm = ~0;
6427dd7cddfSDavid du Colombier 	c->recvaccm = ~0;
6437dd7cddfSDavid du Colombier 
6447dd7cddfSDavid du Colombier 	if(!ipaddralloc(c))
6457dd7cddfSDavid du Colombier 		myfatal("callalloc: could not alloc remote ip address");
6467dd7cddfSDavid du Colombier 
6477dd7cddfSDavid du Colombier 	if(pipe(pfd) < 0)
6487dd7cddfSDavid du Colombier 		myfatal("callalloc: pipe failed: %r");
6497dd7cddfSDavid du Colombier 
6507dd7cddfSDavid du Colombier 	sprint(buf, "%s/ipifc/clone", srv.pppdir);
6517dd7cddfSDavid du Colombier 	fd = open(buf, OWRITE);
6527dd7cddfSDavid du Colombier 	if(fd < 0)
6537dd7cddfSDavid du Colombier 		myfatal("callalloc: could not open %s: %r", buf);
6547dd7cddfSDavid du Colombier 
6557dd7cddfSDavid du Colombier 	n = sprint(buf, "iprouting");
6567dd7cddfSDavid du Colombier 	if(write(fd, buf, n) < n)
6577dd7cddfSDavid du Colombier 		myfatal("callalloc: write to ifc failed: %r");
6587dd7cddfSDavid du Colombier 	close(fd);
6597dd7cddfSDavid du Colombier 
6607dd7cddfSDavid du Colombier 	p = argv;
66180ee5cbfSDavid du Colombier 	*p++ = srv.pppexec;
66259cc4ca5SDavid du Colombier 	*p++ = "-SC";
6637dd7cddfSDavid du Colombier 	*p++ = "-x";
6647dd7cddfSDavid du Colombier 	*p++ = srv.pppdir;
6657dd7cddfSDavid du Colombier 	if(debug)
6667dd7cddfSDavid du Colombier 		*p++ = "-d";
6677dd7cddfSDavid du Colombier 	sprint(local, "%I", srv.ipaddr);
6687dd7cddfSDavid du Colombier 	*p++ = local;
6697dd7cddfSDavid du Colombier 	sprint(remote, "%I", c->remoteip);
6707dd7cddfSDavid du Colombier 	*p++ = remote;
6717dd7cddfSDavid du Colombier 	*p = 0;
6727dd7cddfSDavid du Colombier 
6737dd7cddfSDavid du Colombier 	proc(argv, pfd[0], pfd[0], 2);
6747dd7cddfSDavid du Colombier 
6757dd7cddfSDavid du Colombier 	close(pfd[0]);
6767dd7cddfSDavid du Colombier 
6777dd7cddfSDavid du Colombier 	c->pppfd = pfd[1];
6787dd7cddfSDavid du Colombier 
6797dd7cddfSDavid du Colombier 	c->next = srv.hash[h];
6807dd7cddfSDavid du Colombier 	srv.hash[h] = c;
6817dd7cddfSDavid du Colombier 
6827dd7cddfSDavid du Colombier 	qunlock(&srv.lk);
6837dd7cddfSDavid du Colombier 
6847dd7cddfSDavid du Colombier 	c->ref++;
6857dd7cddfSDavid du Colombier 	thread(pppread, c);
6867dd7cddfSDavid du Colombier 	c->ref++;
6877dd7cddfSDavid du Colombier 	thread(gretimeout, c);
6887dd7cddfSDavid du Colombier 
6897dd7cddfSDavid du Colombier 	syslog(0, LOG, ": src=%I: call started: id=%d: remote ip=%I", srv.remote, id, c->remoteip);
6907dd7cddfSDavid du Colombier 
6917dd7cddfSDavid du Colombier 	return c;
6927dd7cddfSDavid du Colombier }
6937dd7cddfSDavid du Colombier 
6947dd7cddfSDavid du Colombier void
callclose(Call * c)6957dd7cddfSDavid du Colombier callclose(Call *c)
6967dd7cddfSDavid du Colombier {
6977dd7cddfSDavid du Colombier 	Call *oc;
6987dd7cddfSDavid du Colombier 	int id;
6997dd7cddfSDavid du Colombier 	uint h;
7007dd7cddfSDavid du Colombier 
7017dd7cddfSDavid du Colombier 	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",
7027dd7cddfSDavid du Colombier 		srv.remote, c->id, c->stat.send, c->stat.sendack, c->stat.recv, c->stat.recvack,
7037dd7cddfSDavid du Colombier 		c->stat.dropped, c->stat.missing, c->stat.sendwait, c->stat.sendtimeout);
7047dd7cddfSDavid du Colombier 
7057dd7cddfSDavid du Colombier 	qlock(&srv.lk);
7067dd7cddfSDavid du Colombier 	if(c->closed) {
7077dd7cddfSDavid du Colombier 		qunlock(&srv.lk);
7087dd7cddfSDavid du Colombier 		return;
7097dd7cddfSDavid du Colombier 	}
7107dd7cddfSDavid du Colombier 	c->closed = 1;
7117dd7cddfSDavid du Colombier 
7127dd7cddfSDavid du Colombier 	close(c->dhcpfd[0]);
7137dd7cddfSDavid du Colombier 	close(c->dhcpfd[1]);
7147dd7cddfSDavid du Colombier 	close(c->pppfd);
7157dd7cddfSDavid du Colombier 	c->pppfd = -1;
7167dd7cddfSDavid du Colombier 
7177dd7cddfSDavid du Colombier 	h = c->id%Nhash;
7187dd7cddfSDavid du Colombier 	id = c->id;
7197dd7cddfSDavid du Colombier 	for(c=srv.hash[h],oc=0; c; oc=c,c=c->next)
7207dd7cddfSDavid du Colombier 		if(c->id == id)
7217dd7cddfSDavid du Colombier 			break;
7227dd7cddfSDavid du Colombier 	if(oc == 0)
7237dd7cddfSDavid du Colombier 		srv.hash[h] = c->next;
7247dd7cddfSDavid du Colombier 	else
7257dd7cddfSDavid du Colombier 		oc->next = c->next;
7267dd7cddfSDavid du Colombier 	c->next = 0;
7277dd7cddfSDavid du Colombier 	qunlock(&srv.lk);
7287dd7cddfSDavid du Colombier 
7297dd7cddfSDavid du Colombier 	callfree(c);
7307dd7cddfSDavid du Colombier }
7317dd7cddfSDavid du Colombier 
7327dd7cddfSDavid du Colombier void
callfree(Call * c)7337dd7cddfSDavid du Colombier callfree(Call *c)
7347dd7cddfSDavid du Colombier {
7357dd7cddfSDavid du Colombier 	int ref;
7367dd7cddfSDavid du Colombier 
7377dd7cddfSDavid du Colombier 	qlock(&srv.lk);
7387dd7cddfSDavid du Colombier 	ref = --c->ref;
7397dd7cddfSDavid du Colombier 	qunlock(&srv.lk);
7407dd7cddfSDavid du Colombier 	if(ref > 0)
7417dd7cddfSDavid du Colombier 		return;
7427dd7cddfSDavid du Colombier 
7437dd7cddfSDavid du Colombier 	/* already unhooked from hash list - see callclose */
7447dd7cddfSDavid du Colombier 	assert(c->closed == 1);
7457dd7cddfSDavid du Colombier 	assert(ref == 0);
7467dd7cddfSDavid du Colombier 	assert(c->next == 0);
7477dd7cddfSDavid du Colombier 
7487dd7cddfSDavid du Colombier SDB "call free\n" EDB
7497dd7cddfSDavid du Colombier 	free(c);
7507dd7cddfSDavid du Colombier }
7517dd7cddfSDavid du Colombier 
7527dd7cddfSDavid du Colombier Call*
calllookup(int id)7537dd7cddfSDavid du Colombier calllookup(int id)
7547dd7cddfSDavid du Colombier {
7557dd7cddfSDavid du Colombier 	uint h;
7567dd7cddfSDavid du Colombier 	Call *c;
7577dd7cddfSDavid du Colombier 
7587dd7cddfSDavid du Colombier 	h = id%Nhash;
7597dd7cddfSDavid du Colombier 
7607dd7cddfSDavid du Colombier 	qlock(&srv.lk);
7617dd7cddfSDavid du Colombier 	for(c=srv.hash[h]; c; c=c->next)
7627dd7cddfSDavid du Colombier 		if(c->id == id)
7637dd7cddfSDavid du Colombier 			break;
7647dd7cddfSDavid du Colombier 	if(c != 0)
7657dd7cddfSDavid du Colombier 		c->ref++;
7667dd7cddfSDavid du Colombier 	qunlock(&srv.lk);
7677dd7cddfSDavid du Colombier 
7687dd7cddfSDavid du Colombier 	return c;
7697dd7cddfSDavid du Colombier }
7707dd7cddfSDavid du Colombier 
7719a747e4fSDavid du Colombier 
7727dd7cddfSDavid du Colombier void
srvinit(void)7737dd7cddfSDavid du Colombier srvinit(void)
7747dd7cddfSDavid du Colombier {
7757dd7cddfSDavid du Colombier 	char buf[100];
7767dd7cddfSDavid du Colombier 	int fd, n;
7777dd7cddfSDavid du Colombier 
7787dd7cddfSDavid du Colombier 	sprint(buf, "%s/local", srv.tcpdir);
7797dd7cddfSDavid du Colombier 	if((fd = open(buf, OREAD)) < 0)
7807dd7cddfSDavid du Colombier 		myfatal("could not open %s: %r", buf);
7817dd7cddfSDavid du Colombier 	if((n = read(fd, buf, sizeof(buf))) < 0)
7827dd7cddfSDavid du Colombier 		myfatal("could not read %s: %r", buf);
7837dd7cddfSDavid du Colombier 	buf[n] = 0;
7847dd7cddfSDavid du Colombier 	parseip(srv.local, buf);
7857dd7cddfSDavid du Colombier 	close(fd);
7867dd7cddfSDavid du Colombier 
7877dd7cddfSDavid du Colombier 	sprint(buf, "%s/remote", srv.tcpdir);
7887dd7cddfSDavid du Colombier 	if((fd = open(buf, OREAD)) < 0)
7897dd7cddfSDavid du Colombier 		myfatal("could not open %s: %r", buf);
7907dd7cddfSDavid du Colombier 	if((n = read(fd, buf, sizeof(buf))) < 0)
7917dd7cddfSDavid du Colombier 		myfatal("could not read %s: %r", buf);
7927dd7cddfSDavid du Colombier 	buf[n] = 0;
7937dd7cddfSDavid du Colombier 	parseip(srv.remote, buf);
7947dd7cddfSDavid du Colombier 	close(fd);
7957dd7cddfSDavid du Colombier 
7967dd7cddfSDavid du Colombier 	if(srv.pppdir == 0)
7977dd7cddfSDavid du Colombier 		srv.pppdir = "/net";
7987dd7cddfSDavid du Colombier 
79980ee5cbfSDavid du Colombier 	if(srv.pppexec == 0)
80080ee5cbfSDavid du Colombier 		srv.pppexec = "/bin/ip/ppp";
8017dd7cddfSDavid du Colombier 
8029a747e4fSDavid du Colombier 	if(myipaddr(srv.ipaddr, srv.pppdir) < 0)
80380ee5cbfSDavid du Colombier 		myfatal("could not read local ip addr: %r");
8047dd7cddfSDavid du Colombier 	if(srv.recvwindow == 0)
8057dd7cddfSDavid du Colombier 		srv.recvwindow = Window;
8067dd7cddfSDavid du Colombier }
8077dd7cddfSDavid du Colombier 
8087dd7cddfSDavid du Colombier void
greinit(void)8097dd7cddfSDavid du Colombier greinit(void)
8107dd7cddfSDavid du Colombier {
8117dd7cddfSDavid du Colombier 	char addr[100], *p;
8127dd7cddfSDavid du Colombier 	int fd, cfd;
8137dd7cddfSDavid du Colombier 
8147dd7cddfSDavid du Colombier 	SDB "srv.tcpdir = %s\n", srv.tcpdir EDB
8157dd7cddfSDavid du Colombier 	strcpy(addr, srv.tcpdir);
8167dd7cddfSDavid du Colombier 	p = strrchr(addr, '/');
8177dd7cddfSDavid du Colombier 	if(p == 0)
8187dd7cddfSDavid du Colombier 		myfatal("bad tcp dir: %s", srv.tcpdir);
8197dd7cddfSDavid du Colombier 	*p = 0;
8207dd7cddfSDavid du Colombier 	p = strrchr(addr, '/');
8217dd7cddfSDavid du Colombier 	if(p == 0)
8227dd7cddfSDavid du Colombier 		myfatal("bad tcp dir: %s", srv.tcpdir);
8237dd7cddfSDavid du Colombier 	sprint(p, "/gre!%I!34827", srv.remote);
8247dd7cddfSDavid du Colombier 
8257dd7cddfSDavid du Colombier 	SDB "addr = %s\n", addr EDB
8267dd7cddfSDavid du Colombier 
8277dd7cddfSDavid du Colombier 	fd = dial(addr, 0, 0, &cfd);
8287dd7cddfSDavid du Colombier 
8297dd7cddfSDavid du Colombier 	if(fd < 0)
8307dd7cddfSDavid du Colombier 		myfatal("%I: dial %s failed: %r", srv.remote, addr);
8317dd7cddfSDavid du Colombier 
8327dd7cddfSDavid du Colombier 	srv.grefd = fd;
8337dd7cddfSDavid du Colombier 	srv.grecfd = cfd;
8347dd7cddfSDavid du Colombier 
8357dd7cddfSDavid du Colombier 	thread(greread, 0);
8367dd7cddfSDavid du Colombier }
8377dd7cddfSDavid du Colombier 
8387dd7cddfSDavid du Colombier void
greread(void *)8397dd7cddfSDavid du Colombier greread(void *)
8407dd7cddfSDavid du Colombier {
8417dd7cddfSDavid du Colombier 	uchar buf[Pktsize], *p;
8427dd7cddfSDavid du Colombier 	int n, i;
8437dd7cddfSDavid du Colombier 	int flag, prot, len, callid;
8447dd7cddfSDavid du Colombier 	uchar src[IPaddrlen], dst[IPaddrlen];
8457dd7cddfSDavid du Colombier 	uint rseq, ack;
8467dd7cddfSDavid du Colombier 	Call *c;
8477dd7cddfSDavid du Colombier 	static double t, last;
8487dd7cddfSDavid du Colombier 
8497dd7cddfSDavid du Colombier 	for(;;) {
8507dd7cddfSDavid du Colombier 		n = read(srv.grefd, buf, sizeof(buf));
8517dd7cddfSDavid du Colombier 		if(n < 0)
8527dd7cddfSDavid du Colombier 			myfatal("%I: bad read on gre: %r", srv.remote);
8537dd7cddfSDavid du Colombier 		if(n == sizeof(buf))
8547dd7cddfSDavid du Colombier 			myfatal("%I: gre read: buf too small", srv.remote);
8557dd7cddfSDavid du Colombier 
8567dd7cddfSDavid du Colombier 		p = buf;
8577dd7cddfSDavid du Colombier 		v4tov6(src, p);
8587dd7cddfSDavid du Colombier 		v4tov6(dst, p+4);
8597dd7cddfSDavid du Colombier 		flag = GSHORT(p+8);
8607dd7cddfSDavid du Colombier 		prot = GSHORT(p+10);
8617dd7cddfSDavid du Colombier 		p += 12; n -= 12;
8627dd7cddfSDavid du Colombier 
8637dd7cddfSDavid du Colombier 		if(ipcmp(src, srv.remote) != 0 || ipcmp(dst, srv.local) != 0)
8647dd7cddfSDavid du Colombier 			myfatal("%I: gre read bad address src=%I dst=%I", srv.remote, src, dst);
8657dd7cddfSDavid du Colombier 
8667dd7cddfSDavid du Colombier 		if(prot != GRE_ppp)
8677dd7cddfSDavid du Colombier 			myfatal("%I: gre read gave bad protocol", srv.remote);
8687dd7cddfSDavid du Colombier 
8697dd7cddfSDavid du Colombier 		if(flag & (GRE_chksum|GRE_routing)){
8707dd7cddfSDavid du Colombier 			p += 4; n -= 4;
8717dd7cddfSDavid du Colombier 		}
8727dd7cddfSDavid du Colombier 
8737dd7cddfSDavid du Colombier 		if(!(flag&GRE_key))
8747dd7cddfSDavid du Colombier 			myfatal("%I: gre packet does not contain a key: f=%ux",
8757dd7cddfSDavid du Colombier 				srv.remote, flag);
8767dd7cddfSDavid du Colombier 
8777dd7cddfSDavid du Colombier 		len = GSHORT(p);
8787dd7cddfSDavid du Colombier 		callid = GSHORT(p+2);
8797dd7cddfSDavid du Colombier 		p += 4; n -= 4;
8807dd7cddfSDavid du Colombier 
8817dd7cddfSDavid du Colombier 		c = calllookup(callid);
8827dd7cddfSDavid du Colombier 		if(c == 0) {
8837dd7cddfSDavid du Colombier 			SDB "%I: unknown callid: %d\n", srv.remote, callid EDB
8847dd7cddfSDavid du Colombier 			continue;
8857dd7cddfSDavid du Colombier 		}
8867dd7cddfSDavid du Colombier 
8877dd7cddfSDavid du Colombier 		qlock(&c->lk);
8887dd7cddfSDavid du Colombier 
8897dd7cddfSDavid du Colombier 		c->stat.recv++;
8907dd7cddfSDavid du Colombier 
8917dd7cddfSDavid du Colombier 		if(flag&GRE_seq) {
8927dd7cddfSDavid du Colombier 			rseq = GLONG(p);
8937dd7cddfSDavid du Colombier 			p += 4; n -= 4;
8947dd7cddfSDavid du Colombier 		} else
8957dd7cddfSDavid du Colombier 			rseq = c->rseq;
8967dd7cddfSDavid du Colombier 
8977dd7cddfSDavid du Colombier 		if(flag&GRE_ack){
8987dd7cddfSDavid du Colombier 			ack = GLONG(p);
8997dd7cddfSDavid du Colombier 			p += 4; n -= 4;
9007dd7cddfSDavid du Colombier 		} else
9017dd7cddfSDavid du Colombier 			ack = c->ack;
9027dd7cddfSDavid du Colombier 
9037dd7cddfSDavid du Colombier 		/* skip routing if present */
9047dd7cddfSDavid du Colombier 		if(flag&GRE_routing) {
9057dd7cddfSDavid du Colombier 			while((i=p[3]) != 0) {
9067dd7cddfSDavid du Colombier 				n -= i;
9077dd7cddfSDavid du Colombier 				p += i;
9087dd7cddfSDavid du Colombier 			}
9097dd7cddfSDavid du Colombier 		}
9107dd7cddfSDavid du Colombier 
9117dd7cddfSDavid du Colombier 		if(len > n)
9127dd7cddfSDavid du Colombier 			myfatal("%I: bad len in gre packet", srv.remote);
9137dd7cddfSDavid du Colombier 
9147dd7cddfSDavid du Colombier 		if((int)(ack-c->ack) > 0) {
9157dd7cddfSDavid du Colombier 			c->ack = ack;
9167dd7cddfSDavid du Colombier 			esignal(&c->eack);
9177dd7cddfSDavid du Colombier 		}
9187dd7cddfSDavid du Colombier 
9197dd7cddfSDavid du Colombier 		if(debug)
9207dd7cddfSDavid du Colombier 			t = realtime();
9217dd7cddfSDavid du Colombier 
9227dd7cddfSDavid du Colombier 		if(len == 0) {
9237dd7cddfSDavid du Colombier 			/* ack packet */
9247dd7cddfSDavid du Colombier 			c->stat.recvack++;
9257dd7cddfSDavid du Colombier 
9267dd7cddfSDavid du Colombier SDB "%I: %.3f (%.3f): gre %d: recv ack a=%ux n=%d flag=%ux\n", srv.remote, t, t-last,
9277dd7cddfSDavid du Colombier 	c->id, ack, n, flag EDB
9287dd7cddfSDavid du Colombier 
9297dd7cddfSDavid du Colombier 		} else {
9307dd7cddfSDavid du Colombier 
9317dd7cddfSDavid du Colombier SDB "%I: %.3f (%.3f): gre %d: recv s=%ux a=%ux len=%d\n", srv.remote, t, t-last,
9327dd7cddfSDavid du Colombier 	c->id, rseq, ack, len EDB
9337dd7cddfSDavid du Colombier 
9347dd7cddfSDavid du Colombier 			/*
9357dd7cddfSDavid du Colombier 			 * the following handles the case of a single pair of packets
9367dd7cddfSDavid du Colombier 			 * received out of order
9377dd7cddfSDavid du Colombier 			 */
9387dd7cddfSDavid du Colombier 			n = rseq-c->rseq;
9397dd7cddfSDavid du Colombier 			if(n > 0 && (drop == 0. || frand() > drop)) {
9407dd7cddfSDavid du Colombier 				c->stat.missing += n-1;
9417dd7cddfSDavid du Colombier 				/* current packet */
9427dd7cddfSDavid du Colombier 				write(c->pppfd, p, len);
9437dd7cddfSDavid du Colombier 			} else {
9447dd7cddfSDavid du Colombier 				/* out of sequence - drop on the floor */
9457dd7cddfSDavid du Colombier 				c->stat.dropped++;
9467dd7cddfSDavid du Colombier 
9477dd7cddfSDavid du Colombier SDB "%I: %.3f: gre %d: recv out of order or dup packet: seq=%ux len=%d\n",
9487dd7cddfSDavid du Colombier srv.remote, realtime(), c->id, rseq, len EDB
9497dd7cddfSDavid du Colombier 
9507dd7cddfSDavid du Colombier 			}
9517dd7cddfSDavid du Colombier 		}
9527dd7cddfSDavid du Colombier 
9537dd7cddfSDavid du Colombier 		if((int)(rseq-c->rseq) > 0)
9547dd7cddfSDavid du Colombier 			c->rseq = rseq;
9557dd7cddfSDavid du Colombier 
9567dd7cddfSDavid du Colombier 		if(debug)
9577dd7cddfSDavid du Colombier 			last=t;
9587dd7cddfSDavid du Colombier 
9597dd7cddfSDavid du Colombier 		/* open up client window */
9607dd7cddfSDavid du Colombier 		if((int)(c->rseq-c->rack) > (c->recvwindow>>1))
9617dd7cddfSDavid du Colombier 			greack(c);
9627dd7cddfSDavid du Colombier 
9637dd7cddfSDavid du Colombier 		qunlock(&c->lk);
9647dd7cddfSDavid du Colombier 
9657dd7cddfSDavid du Colombier 
9667dd7cddfSDavid du Colombier 		callfree(c);
9677dd7cddfSDavid du Colombier 	}
9687dd7cddfSDavid du Colombier }
9697dd7cddfSDavid du Colombier 
9707dd7cddfSDavid du Colombier void
greack(Call * c)9717dd7cddfSDavid du Colombier greack(Call *c)
9727dd7cddfSDavid du Colombier {
9737dd7cddfSDavid du Colombier 	uchar buf[20];
9747dd7cddfSDavid du Colombier 
9757dd7cddfSDavid du Colombier 	c->stat.sendack++;
9767dd7cddfSDavid du Colombier 
9777dd7cddfSDavid du Colombier SDB "%I: %.3f: gre %d: send ack %ux\n", srv.remote, realtime(), c->id, c->rseq EDB
9787dd7cddfSDavid du Colombier 
9797dd7cddfSDavid du Colombier 	v6tov4(buf+0, srv.local);		/* source */
9807dd7cddfSDavid du Colombier 	v6tov4(buf+4, srv.remote);		/* source */
9817dd7cddfSDavid du Colombier 	PSHORT(buf+8, GRE_key|GRE_ack|1);
9827dd7cddfSDavid du Colombier 	PSHORT(buf+10, GRE_ppp);
9837dd7cddfSDavid du Colombier 	PSHORT(buf+12, 0);
9847dd7cddfSDavid du Colombier 	PSHORT(buf+14, c->id);
9857dd7cddfSDavid du Colombier 	PLONG(buf+16, c->rseq);
9867dd7cddfSDavid du Colombier 
9877dd7cddfSDavid du Colombier 	write(srv.grefd, buf, sizeof(buf));
9887dd7cddfSDavid du Colombier 
9897dd7cddfSDavid du Colombier 	c->rack = c->rseq;
9907dd7cddfSDavid du Colombier 
9917dd7cddfSDavid du Colombier }
9927dd7cddfSDavid du Colombier 
9937dd7cddfSDavid du Colombier void
gretimeout(void * a)9947dd7cddfSDavid du Colombier gretimeout(void *a)
9957dd7cddfSDavid du Colombier {
9967dd7cddfSDavid du Colombier 	Call *c;
9977dd7cddfSDavid du Colombier 
9987dd7cddfSDavid du Colombier 	c = a;
9997dd7cddfSDavid du Colombier 
10007dd7cddfSDavid du Colombier 	while(!c->closed) {
10017dd7cddfSDavid du Colombier 		sleep(Tick);
10027dd7cddfSDavid du Colombier 		qlock(&c->lk);
10037dd7cddfSDavid du Colombier 		c->tick++;
10047dd7cddfSDavid du Colombier 		qunlock(&c->lk);
10057dd7cddfSDavid du Colombier 		esignal(&c->eack);
10067dd7cddfSDavid du Colombier 	}
10077dd7cddfSDavid du Colombier 	callfree(c);
10087dd7cddfSDavid du Colombier 	exits(0);
10097dd7cddfSDavid du Colombier }
10107dd7cddfSDavid du Colombier 
10117dd7cddfSDavid du Colombier 
10127dd7cddfSDavid du Colombier void
pppread(void * a)10137dd7cddfSDavid du Colombier pppread(void *a)
10147dd7cddfSDavid du Colombier {
10157dd7cddfSDavid du Colombier 	Call *c;
10167dd7cddfSDavid du Colombier 	uchar buf[2000], *p;
10177dd7cddfSDavid du Colombier 	int n;
10187dd7cddfSDavid du Colombier 	ulong tick;
10197dd7cddfSDavid du Colombier 
10207dd7cddfSDavid du Colombier 	c = a;
10217dd7cddfSDavid du Colombier 	for(;;) {
10227dd7cddfSDavid du Colombier 		p = buf+24;
10237dd7cddfSDavid du Colombier 		n = read(c->pppfd, p, sizeof(buf)-24);
10247dd7cddfSDavid du Colombier 		if(n <= 0)
10257dd7cddfSDavid du Colombier 			break;
10267dd7cddfSDavid du Colombier 
10277dd7cddfSDavid du Colombier 		qlock(&c->lk);
10287dd7cddfSDavid du Colombier 
10297dd7cddfSDavid du Colombier 		/* add gre header */
10307dd7cddfSDavid du Colombier 		c->seq++;
10317dd7cddfSDavid du Colombier 		tick = c->tick;
10327dd7cddfSDavid du Colombier 
10337dd7cddfSDavid du Colombier 		while(c->seq-c->ack>c->sendwindow && c->tick-tick<Sendtimeout && !c->closed) {
10347dd7cddfSDavid du Colombier 			c->stat.sendwait++;
10357dd7cddfSDavid du Colombier SDB "window full seq = %d ack = %ux window = %ux\n", c->seq, c->ack, c->sendwindow EDB
10367dd7cddfSDavid du Colombier 			qunlock(&c->lk);
10377dd7cddfSDavid du Colombier 			ewait(&c->eack);
10387dd7cddfSDavid du Colombier 			qlock(&c->lk);
10397dd7cddfSDavid du Colombier 		}
10407dd7cddfSDavid du Colombier 
10417dd7cddfSDavid du Colombier 		if(c->tick-tick >= Sendtimeout) {
10427dd7cddfSDavid du Colombier 			c->stat.sendtimeout++;
10437dd7cddfSDavid du Colombier SDB "send timeout = %d ack = %ux window = %ux\n", c->seq, c->ack, c->sendwindow EDB
10447dd7cddfSDavid du Colombier 		}
10457dd7cddfSDavid du Colombier 
10467dd7cddfSDavid du Colombier 		v6tov4(buf+0, srv.local);		/* source */
10477dd7cddfSDavid du Colombier 		v6tov4(buf+4, srv.remote);		/* source */
10487dd7cddfSDavid du Colombier 		PSHORT(buf+8, GRE_key|GRE_seq|GRE_ack|1);
10497dd7cddfSDavid du Colombier 		PSHORT(buf+10, GRE_ppp);
10507dd7cddfSDavid du Colombier 		PSHORT(buf+12, n);
10517dd7cddfSDavid du Colombier 		PSHORT(buf+14, c->id);
10527dd7cddfSDavid du Colombier 		PLONG(buf+16, c->seq);
10537dd7cddfSDavid du Colombier 		PLONG(buf+20, c->rseq);
10547dd7cddfSDavid du Colombier 
10557dd7cddfSDavid du Colombier 		c->stat.send++;
10567dd7cddfSDavid du Colombier 		c->rack = c->rseq;
10577dd7cddfSDavid du Colombier 
10587dd7cddfSDavid du Colombier SDB "%I: %.3f: gre %d: send s=%ux a=%ux len=%d\n", srv.remote, realtime(),
10597dd7cddfSDavid du Colombier 	c->id,  c->seq, c->rseq, n EDB
10607dd7cddfSDavid du Colombier 
10617dd7cddfSDavid du Colombier 		if(drop == 0. || frand() > drop)
10627dd7cddfSDavid du Colombier 			if(write(srv.grefd, buf, n+24)<n+24)
10637dd7cddfSDavid du Colombier 				myfatal("pppread: write failed: %r");
10647dd7cddfSDavid du Colombier 
10657dd7cddfSDavid du Colombier 		qunlock(&c->lk);
10667dd7cddfSDavid du Colombier 	}
10677dd7cddfSDavid du Colombier 
10687dd7cddfSDavid du Colombier 	SDB "pppread exit: %d\n", c->id);
10697dd7cddfSDavid du Colombier 
10707dd7cddfSDavid du Colombier 	callfree(c);
10717dd7cddfSDavid du Colombier 	exits(0);
10727dd7cddfSDavid du Colombier }
10737dd7cddfSDavid du Colombier 
10747dd7cddfSDavid du Colombier void
timeoutthread(void *)10757dd7cddfSDavid du Colombier timeoutthread(void*)
10767dd7cddfSDavid du Colombier {
10777dd7cddfSDavid du Colombier 	for(;;) {
10787dd7cddfSDavid du Colombier 		sleep(30*1000);
10797dd7cddfSDavid du Colombier 
10807dd7cddfSDavid du Colombier 		qlock(&srv.lk);
10817dd7cddfSDavid du Colombier 		if(realtime() - srv.rcvtime > 5*60)
10827dd7cddfSDavid du Colombier 			myfatal("server timedout");
10837dd7cddfSDavid du Colombier 		qunlock(&srv.lk);
10847dd7cddfSDavid du Colombier 	}
10857dd7cddfSDavid du Colombier }
10867dd7cddfSDavid du Colombier 
10877dd7cddfSDavid du Colombier 
10887dd7cddfSDavid du Colombier /* use syslog() rather than fprint(2, ...) */
10897dd7cddfSDavid du Colombier void
myfatal(char * fmt,...)10907dd7cddfSDavid du Colombier myfatal(char *fmt, ...)
10917dd7cddfSDavid du Colombier {
10927dd7cddfSDavid du Colombier 	char sbuf[512];
10937dd7cddfSDavid du Colombier 	va_list arg;
10947dd7cddfSDavid du Colombier 	uchar buf[16];
10957dd7cddfSDavid du Colombier 
10967dd7cddfSDavid du Colombier 	/* NT don't seem to like us just going away */
10977dd7cddfSDavid du Colombier 	memset(buf, 0, sizeof(buf));
10987dd7cddfSDavid du Colombier 	PSHORT(buf+0, sizeof(buf));	/* length */
10997dd7cddfSDavid du Colombier 	PSHORT(buf+2, 1);		/* message type */
11007dd7cddfSDavid du Colombier 	PLONG(buf+4, Magic);		/* magic */
11017dd7cddfSDavid du Colombier 	PSHORT(buf+8, Tstop);		/* op */
11027dd7cddfSDavid du Colombier 	buf[12] = 3;			/* local shutdown */
11037dd7cddfSDavid du Colombier 
11047dd7cddfSDavid du Colombier 	write(1, buf, sizeof(buf));
11057dd7cddfSDavid du Colombier 
11067dd7cddfSDavid du Colombier 	va_start(arg, fmt);
11079a747e4fSDavid du Colombier 	vseprint(sbuf, sbuf+sizeof(sbuf), fmt, arg);
11087dd7cddfSDavid du Colombier 	va_end(arg);
11097dd7cddfSDavid du Colombier 
11107dd7cddfSDavid du Colombier 	SDB "%I: fatal: %s\n", srv.remote, sbuf EDB
11117dd7cddfSDavid du Colombier 	syslog(0, LOG, ": src=%I: fatal: %s", srv.remote, sbuf);
11127dd7cddfSDavid du Colombier 
11137dd7cddfSDavid du Colombier 	close(0);
11147dd7cddfSDavid du Colombier 	close(1);
11157dd7cddfSDavid du Colombier 	close(srv.grefd);
11167dd7cddfSDavid du Colombier 	close(srv.grecfd);
11177dd7cddfSDavid du Colombier 
11187dd7cddfSDavid du Colombier 	postnote(PNGROUP, getpid(), "die");
11197dd7cddfSDavid du Colombier 	exits(sbuf);
11207dd7cddfSDavid du Colombier }
11217dd7cddfSDavid du Colombier 
11227dd7cddfSDavid du Colombier int
argatoi(char * p)11237dd7cddfSDavid du Colombier argatoi(char *p)
11247dd7cddfSDavid du Colombier {
11257dd7cddfSDavid du Colombier 	char *q;
11267dd7cddfSDavid du Colombier 	int i;
11277dd7cddfSDavid du Colombier 
11287dd7cddfSDavid du Colombier 	if(p == 0)
11297dd7cddfSDavid du Colombier 		usage();
11307dd7cddfSDavid du Colombier 
11317dd7cddfSDavid du Colombier 	i = strtol(p, &q, 0);
11327dd7cddfSDavid du Colombier 	if(q == p)
11337dd7cddfSDavid du Colombier 		usage();
11347dd7cddfSDavid du Colombier 	return i;
11357dd7cddfSDavid du Colombier }
11367dd7cddfSDavid du Colombier 
11377dd7cddfSDavid du Colombier void
dhcpclientwatch(void * a)11387dd7cddfSDavid du Colombier dhcpclientwatch(void *a)
11397dd7cddfSDavid du Colombier {
11407dd7cddfSDavid du Colombier 	Call *c = a;
11417dd7cddfSDavid du Colombier 	uchar buf[1];
11427dd7cddfSDavid du Colombier 
11437dd7cddfSDavid du Colombier 	for(;;) {
11447dd7cddfSDavid du Colombier 		if(read(c->dhcpfd[0], buf, sizeof(buf)) <= 0)
11457dd7cddfSDavid du Colombier 			break;
11467dd7cddfSDavid du Colombier 	}
11477dd7cddfSDavid du Colombier 	if(!c->closed)
11487dd7cddfSDavid du Colombier 		myfatal("dhcpclient terminated");
11497dd7cddfSDavid du Colombier 	callfree(c);
11507dd7cddfSDavid du Colombier 	exits(0);
11517dd7cddfSDavid du Colombier }
11527dd7cddfSDavid du Colombier 
11537dd7cddfSDavid du Colombier int
ipaddralloc(Call * c)11547dd7cddfSDavid du Colombier ipaddralloc(Call *c)
11557dd7cddfSDavid du Colombier {
11567dd7cddfSDavid du Colombier 	int pfd[2][2];
11577dd7cddfSDavid du Colombier 	char *argv[4], *p;
11587dd7cddfSDavid du Colombier 	Biobuf bio;
11597dd7cddfSDavid du Colombier 
11607dd7cddfSDavid du Colombier 	argv[0] = "/bin/ip/dhcpclient";
11617dd7cddfSDavid du Colombier 	argv[1] = "-x";
11627dd7cddfSDavid du Colombier 	argv[2] = srv.pppdir;
11637dd7cddfSDavid du Colombier 	argv[3] = 0;
11647dd7cddfSDavid du Colombier 
11657dd7cddfSDavid du Colombier 	if(pipe(pfd[0])<0)
11667dd7cddfSDavid du Colombier 		myfatal("ipaddralloc: pipe failed: %r");
11677dd7cddfSDavid du Colombier 	if(pipe(pfd[1])<0)
11687dd7cddfSDavid du Colombier 		myfatal("ipaddralloc: pipe failed: %r");
11697dd7cddfSDavid du Colombier 
11707dd7cddfSDavid du Colombier 	if(proc(argv, pfd[0][0], pfd[1][1], 2) < 0)
11717dd7cddfSDavid du Colombier 		myfatal("ipaddralloc: proc failed: %r");
11727dd7cddfSDavid du Colombier 
11737dd7cddfSDavid du Colombier 	close(pfd[0][0]);
11747dd7cddfSDavid du Colombier 	close(pfd[1][1]);
11757dd7cddfSDavid du Colombier 	c->dhcpfd[0] = pfd[1][0];
11767dd7cddfSDavid du Colombier 	c->dhcpfd[1] = pfd[0][1];
11777dd7cddfSDavid du Colombier 
11787dd7cddfSDavid du Colombier 	Binit(&bio, pfd[1][0], OREAD);
11797dd7cddfSDavid du Colombier 	for(;;) {
11807dd7cddfSDavid du Colombier 		p = Brdline(&bio, '\n');
11817dd7cddfSDavid du Colombier 		if(p == 0)
11827dd7cddfSDavid du Colombier 			break;
11837dd7cddfSDavid du Colombier 		if(strncmp(p, "ip=", 3) == 0) {
11847dd7cddfSDavid du Colombier 			p += 3;
11857dd7cddfSDavid du Colombier 			parseip(c->remoteip, p);
11867dd7cddfSDavid du Colombier 		} else if(strncmp(p, "end\n", 4) == 0)
11877dd7cddfSDavid du Colombier 			break;
11887dd7cddfSDavid du Colombier 	}
11897dd7cddfSDavid du Colombier 
11907dd7cddfSDavid du Colombier 	Bterm(&bio);
11917dd7cddfSDavid du Colombier 
11927dd7cddfSDavid du Colombier 	c->ref++;
11937dd7cddfSDavid du Colombier 
11947dd7cddfSDavid du Colombier 	thread(dhcpclientwatch, c);
11957dd7cddfSDavid du Colombier 
11967dd7cddfSDavid du Colombier 	return ipcmp(c->remoteip, IPnoaddr) != 0;
11977dd7cddfSDavid du Colombier }
11987dd7cddfSDavid du Colombier 
11997dd7cddfSDavid du Colombier 
12007dd7cddfSDavid du Colombier void
esignal(Event * e)12017dd7cddfSDavid du Colombier esignal(Event *e)
12027dd7cddfSDavid du Colombier {
12037dd7cddfSDavid du Colombier 	qlock(e);
12047dd7cddfSDavid du Colombier 	if(e->wait == 0) {
12057dd7cddfSDavid du Colombier 		e->ready = 1;
12067dd7cddfSDavid du Colombier 		qunlock(e);
12077dd7cddfSDavid du Colombier 		return;
12087dd7cddfSDavid du Colombier 	}
12097dd7cddfSDavid du Colombier 	assert(e->ready == 0);
12107dd7cddfSDavid du Colombier 	e->wait = 0;
121174f16c81SDavid du Colombier 	rendezvous(e, (void*)1);
12127dd7cddfSDavid du Colombier 	qunlock(e);
12137dd7cddfSDavid du Colombier }
12147dd7cddfSDavid du Colombier 
12157dd7cddfSDavid du Colombier void
ewait(Event * e)12167dd7cddfSDavid du Colombier ewait(Event *e)
12177dd7cddfSDavid du Colombier {
12187dd7cddfSDavid du Colombier 	qlock(&e->waitlk);
12197dd7cddfSDavid du Colombier 	qlock(e);
12207dd7cddfSDavid du Colombier 	assert(e->wait == 0);
12217dd7cddfSDavid du Colombier 	if(e->ready) {
12227dd7cddfSDavid du Colombier 		e->ready = 0;
12237dd7cddfSDavid du Colombier 	} else {
12247dd7cddfSDavid du Colombier 		e->wait = 1;
12257dd7cddfSDavid du Colombier 		qunlock(e);
122674f16c81SDavid du Colombier 		rendezvous(e, (void*)2);
12277dd7cddfSDavid du Colombier 		qlock(e);
12287dd7cddfSDavid du Colombier 	}
12297dd7cddfSDavid du Colombier 	qunlock(e);
12307dd7cddfSDavid du Colombier 	qunlock(&e->waitlk);
12317dd7cddfSDavid du Colombier }
12327dd7cddfSDavid du Colombier 
12337dd7cddfSDavid du Colombier ulong
thread(void (* f)(void *),void * a)12347dd7cddfSDavid du Colombier thread(void(*f)(void*), void *a)
12357dd7cddfSDavid du Colombier {
12367dd7cddfSDavid du Colombier 	int pid;
12377dd7cddfSDavid du Colombier 	pid=rfork(RFNOWAIT|RFMEM|RFPROC);
12387dd7cddfSDavid du Colombier 	if(pid < 0)
12397dd7cddfSDavid du Colombier 		myfatal("rfork failed: %r");
12407dd7cddfSDavid du Colombier 	if(pid != 0)
12417dd7cddfSDavid du Colombier 		return pid;
12427dd7cddfSDavid du Colombier 	(*f)(a);
12437dd7cddfSDavid du Colombier 	return 0; // never reaches here
12447dd7cddfSDavid du Colombier }
12457dd7cddfSDavid du Colombier 
12467dd7cddfSDavid du Colombier double
realtime(void)12477dd7cddfSDavid du Colombier realtime(void)
12487dd7cddfSDavid du Colombier {
12497dd7cddfSDavid du Colombier 	long times(long*);
12507dd7cddfSDavid du Colombier 
12517dd7cddfSDavid du Colombier 	return times(0) / 1000.0;
12527dd7cddfSDavid du Colombier }
12537dd7cddfSDavid du Colombier 
12547dd7cddfSDavid du Colombier void *
emallocz(int size)12557dd7cddfSDavid du Colombier emallocz(int size)
12567dd7cddfSDavid du Colombier {
12577dd7cddfSDavid du Colombier 	void *p;
12587dd7cddfSDavid du Colombier 	p = malloc(size);
12597dd7cddfSDavid du Colombier 	if(p == 0)
12607dd7cddfSDavid du Colombier 		myfatal("malloc failed: %r");
12617dd7cddfSDavid du Colombier 	memset(p, 0, size);
12627dd7cddfSDavid du Colombier 	return p;
12637dd7cddfSDavid du Colombier }
12647dd7cddfSDavid du Colombier 
12657dd7cddfSDavid du Colombier static void
fdclose(void)12667dd7cddfSDavid du Colombier fdclose(void)
12677dd7cddfSDavid du Colombier {
12687dd7cddfSDavid du Colombier 	int fd, n, i;
12699a747e4fSDavid du Colombier 	Dir *d, *p;
12707dd7cddfSDavid du Colombier 
12717dd7cddfSDavid du Colombier 	if((fd = open("#d", OREAD)) < 0)
12727dd7cddfSDavid du Colombier 		return;
12737dd7cddfSDavid du Colombier 
12749a747e4fSDavid du Colombier 	n = dirreadall(fd, &d);
12759a747e4fSDavid du Colombier 	for(p = d; n > 0; n--, p++) {
12767dd7cddfSDavid du Colombier 		i = atoi(p->name);
12777dd7cddfSDavid du Colombier 		if(i > 2)
12787dd7cddfSDavid du Colombier 			close(i);
12797dd7cddfSDavid du Colombier 	}
12809a747e4fSDavid du Colombier 	free(d);
12817dd7cddfSDavid du Colombier }
12827dd7cddfSDavid du Colombier 
12837dd7cddfSDavid du Colombier int
proc(char ** argv,int fd0,int fd1,int fd2)12847dd7cddfSDavid du Colombier proc(char **argv, int fd0, int fd1, int fd2)
12857dd7cddfSDavid du Colombier {
12867dd7cddfSDavid du Colombier 	int r, flag;
12877dd7cddfSDavid du Colombier 	char *arg0, file[200];
12887dd7cddfSDavid du Colombier 
12897dd7cddfSDavid du Colombier 	arg0 = argv[0];
12907dd7cddfSDavid du Colombier 
12917dd7cddfSDavid du Colombier 	strcpy(file, arg0);
12927dd7cddfSDavid du Colombier 
12937dd7cddfSDavid du Colombier 	if(access(file, 1) < 0) {
12947dd7cddfSDavid du Colombier 		if(strncmp(arg0, "/", 1)==0
12957dd7cddfSDavid du Colombier 		|| strncmp(arg0, "#", 1)==0
12967dd7cddfSDavid du Colombier 		|| strncmp(arg0, "./", 2)==0
12977dd7cddfSDavid du Colombier 		|| strncmp(arg0, "../", 3)==0)
12987dd7cddfSDavid du Colombier 			return 0;
12997dd7cddfSDavid du Colombier 		sprint(file, "/bin/%s", arg0);
13007dd7cddfSDavid du Colombier 		if(access(file, 1) < 0)
13017dd7cddfSDavid du Colombier 			return 0;
13027dd7cddfSDavid du Colombier 	}
13037dd7cddfSDavid du Colombier 
13047dd7cddfSDavid du Colombier 	flag = RFPROC|RFFDG|RFENVG|RFNOWAIT;
13057dd7cddfSDavid du Colombier 	if((r = rfork(flag)) != 0) {
13067dd7cddfSDavid du Colombier 		if(r < 0)
13077dd7cddfSDavid du Colombier 			return 0;
13087dd7cddfSDavid du Colombier 		return r;
13097dd7cddfSDavid du Colombier 	}
13107dd7cddfSDavid du Colombier 
13117dd7cddfSDavid du Colombier 	if(fd0 != 0) {
13127dd7cddfSDavid du Colombier 		if(fd1 == 0)
13137dd7cddfSDavid du Colombier 			fd1 = dup(0, -1);
13147dd7cddfSDavid du Colombier 		if(fd2 == 0)
13157dd7cddfSDavid du Colombier 			fd2 = dup(0, -1);
13167dd7cddfSDavid du Colombier 		close(0);
13177dd7cddfSDavid du Colombier 		if(fd0 >= 0)
13187dd7cddfSDavid du Colombier 			dup(fd0, 0);
13197dd7cddfSDavid du Colombier 	}
13207dd7cddfSDavid du Colombier 
13217dd7cddfSDavid du Colombier 	if(fd1 != 1) {
13227dd7cddfSDavid du Colombier 		if(fd2 == 1)
13237dd7cddfSDavid du Colombier 			fd2 = dup(1, -1);
13247dd7cddfSDavid du Colombier 		close(1);
13257dd7cddfSDavid du Colombier 		if(fd1 >= 0)
13267dd7cddfSDavid du Colombier 			dup(fd1, 1);
13277dd7cddfSDavid du Colombier 	}
13287dd7cddfSDavid du Colombier 
13297dd7cddfSDavid du Colombier 	if(fd2 != 2) {
13307dd7cddfSDavid du Colombier 		close(2);
13317dd7cddfSDavid du Colombier 		if(fd2 >= 0)
13327dd7cddfSDavid du Colombier 			dup(fd2, 2);
13337dd7cddfSDavid du Colombier 	}
13347dd7cddfSDavid du Colombier 
13357dd7cddfSDavid du Colombier 	fdclose();
13367dd7cddfSDavid du Colombier 
13377dd7cddfSDavid du Colombier 	exec(file, argv);
13387dd7cddfSDavid du Colombier 	myfatal("proc: exec failed: %r");
13397dd7cddfSDavid du Colombier 	return 0;
13407dd7cddfSDavid du Colombier }
13417dd7cddfSDavid du Colombier 
1342