1350 lines · 23.4 KB · C
RawDownload
/*  * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #include <u.h>#include <libc.h>#include <bio.h>#include <ip.h> #define	LOG	"pptpd" typedef struct Call	Call;typedef struct Event Event; #define	SDB	if(debug) fprint(2, #define EDB	); enum {	Magic	= 0x1a2b3c4d,	Nhash	= 17,	Nchan	= 10,		/* maximum number of channels */	Window	= 8,		/* default window size */	Timeout	= 60,		/* timeout in seconds for control channel */	Pktsize = 2000,		/* maximum packet size */	Tick	= 500,		/* tick length in milliseconds */	Sendtimeout = 4,	/* in ticks */}; enum {	Syncframe	= 0x1,	Asyncframe	= 0x2,	Analog		= 0x1,	Digital		= 0x2,	Version		= 0x100,}; enum {	Tstart		= 1,	Rstart		= 2,	Tstop		= 3,	Rstop		= 4,	Techo		= 5,	Recho		= 6,	Tcallout	= 7,	Rcallout	= 8,	Tcallreq	= 9,	Rcallreq	= 10,	Acallcon	= 11,	Tcallclear	= 12,	Acalldis	= 13,	Awaninfo	= 14,	Alinkinfo	= 15,};  struct Event {	QLock;	QLock waitlk;	int	wait;	int ready;}; struct Call {	int	ref;	QLock	lk;	int	id;	int	serial;	int	pppfd; 	int	closed; 	int	pac;	/* server is acting as a PAC */ 	int	recvwindow;	/* recv windows */	int	sendwindow;	/* send windows */	int	delay; 	int	sendaccm;	int	recvaccm; 	uint	seq;		/* current seq number - for send */	uint	ack;		/* current acked mesg - for send */	uint	rseq;		/* highest recv seq number for in order packet  */	uint	rack;		/* highest ack sent */ 	Event	eack;		/* recved ack - for send */	ulong	tick; 	uchar	remoteip[IPaddrlen];	/* remote ip address */	int	dhcpfd[2];	/* pipe to dhcpclient */ 	/* error stats */	struct {		int	crc;		int	frame;		int	hardware;		int	overrun;		int	timeout;		int	align;	} err; 	struct {		int	send;		int	sendack;		int	recv;		int	recvack;		int	dropped;		int	missing;		int	sendwait;		int	sendtimeout;	} stat; 	Call	*next;}; struct {	QLock	lk;	int	start;	int	grefd;	int	grecfd;	uchar	local[IPaddrlen];	uchar	remote[IPaddrlen];	char	*tcpdir;	uchar	ipaddr[IPaddrlen];		/* starting ip addresss to allocate */ 	int	recvwindow; 	char	*pppdir;	char	*pppexec; 	double	rcvtime;	/* time at which last request was received */	int	echoid;		/* id of last echo request */ 	Call	*hash[Nhash];} srv; /* GRE flag bits */enum {	GRE_chksum	= (1<<15),	GRE_routing	= (1<<14),	GRE_key		= (1<<13),	GRE_seq		= (1<<12),	GRE_srcrt	= (1<<11),	GRE_recur	= (7<<8),	GRE_ack		= (1<<7),	GRE_ver		= 0x7,}; /* GRE protocols */enum {	GRE_ppp		= 0x880b,}; int	debug;double	drop; void	myfatal(char *fmt, ...); #define	PSHORT(p, v)		((p)[0]=((v)>>8), (p)[1]=(v))#define	PLONG(p, v)		(PSHORT(p, (v)>>16), PSHORT(p+2, (v)))#define	PSTRING(d,s,n)		strncpy((char*)(d), s, n)#define	GSHORT(p)		(((p)[0]<<8) | ((p)[1]<<0))#define	GLONG(p)		((GSHORT((p))<<16) | ((GSHORT((p)+2))<<0))#define	GSTRING(d,s,n)		strncpy(d, (char*)(s), n), d[(n)-1] = 0 void	serve(void); int	sstart(uchar*, int);int	sstop(uchar*, int);int	secho(uchar*, int);int	scallout(uchar*, int);int	scallreq(uchar*, int);int	scallcon(uchar*, int);int	scallclear(uchar*, int);int	scalldis(uchar*, int);int	swaninfo(uchar*, int);int	slinkinfo(uchar*, int); Call	*callalloc(int id);void	callclose(Call*);void	callfree(Call*);Call	*calllookup(int id); void	gretimeout(void*);void	pppread(void*); void	srvinit(void);void	greinit(void);void	greread(void*);void	greack(Call *c); void	timeoutthread(void*); int	argatoi(char *p);void	usage(void);int	ipaddralloc(Call *c); void	*emallocz(int size);void	esignal(Event *e);void	ewait(Event *e);int	proc(char **argv, int fd0, int fd1, int fd2);double	realtime(void);ulong	thread(void(*f)(void*), void *a); voidmain(int argc, char *argv[]){	ARGBEGIN{	case 'd': debug++; break;	case 'p': srv.pppdir = ARGF(); break;	case 'P': srv.pppexec = ARGF(); break;	case 'w': srv.recvwindow = argatoi(ARGF()); break;	case 'D': drop = atof(ARGF()); break;	default:		usage();	}ARGEND 	fmtinstall('I', eipfmt);	fmtinstall('E', eipfmt);	fmtinstall('V', eipfmt);	fmtinstall('M', eipfmt); 	rfork(RFNOTEG|RFREND); 	if(argc != 1)		usage(); 	srv.tcpdir = argv[0]; 	srvinit(); 	syslog(0, LOG, ": src=%I: pptp started: %d", srv.remote, getpid()); 	SDB  "\n\n\n%I: pptp started\n", srv.remote EDB 	greinit(); 	thread(timeoutthread, 0); 	serve(); 	syslog(0, LOG, ": src=%I: server exits", srv.remote); 	exits(0);} voidusage(void){	fprint(2, "usage: pptpd [-dD] [-p ppp-net] [-w window] tcpdir\n");	exits("usage");} voidserve(void){	uchar buf[2000], *p;	int n, n2, len;	int magic;	int op, type; 	n = 0;	for(;;) {		n2 = read(0, buf+n, sizeof(buf)-n);		if(n2 < 0)			myfatal("bad read on ctl channel: %r");		if(n2 == 0)			break;		n += n2;		p = buf;		for(;;) {			if(n < 12)				break; 			qlock(&srv.lk);			srv.rcvtime = realtime();			qunlock(&srv.lk); 			len = GSHORT(p);			type = GSHORT(p+2);			magic = GLONG(p+4);			op = GSHORT(p+8);			if(magic != Magic)				myfatal("bad magic number: got %x", magic);			if(type != 1)				myfatal("bad message type: %d", type);			switch(op) {			default:				myfatal("unknown control op: %d", op);			case Tstart:		/* start-control-connection-request */				n2 = sstart(p, n);				break;			case Tstop:				n2 = sstop(p, n);				if(n2 > 0)					return;				break;			case Techo:				n2 = secho(p, n);				break;			case Tcallout:				n2 = scallout(p, n);				break;			case Tcallreq:				n2 = scallreq(p, n);				break;			case Acallcon:				n2 = scallcon(p, n);				break;			case Tcallclear:				n2 = scallclear(p, n);				break;			case Acalldis:				n2 = scalldis(p, n);				break;			case Awaninfo:				n2 = swaninfo(p, n);				break;			case Alinkinfo:				n2 = slinkinfo(p, n);				break;			}				if(n2 == 0)				break;			if(n2 != len)				myfatal("op=%d: bad length: got %d expected %d", op, len, n2);			n -= n2;			p += n2;					} 		/* move down partial message */		if(p != buf && n != 0)			memmove(buf, p, n);	} } intsstart(uchar *p, int n){	int ver, frame, bearer, maxchan, firm;	char host[64], vendor[64], *sysname;	uchar buf[156]; 	if(n < 156)		return 0;	ver = GSHORT(p+12);	frame = GLONG(p+16);	bearer = GLONG(p+20);	maxchan = GSHORT(p+24);	firm = GSHORT(p+26);	GSTRING(host, p+28, 64);	GSTRING(vendor, p+92, 64); 	SDB "%I: start ver = %x f = %d b = %d maxchan = %d firm = %d host = %s vendor = %s\n",		srv.remote, ver, frame, bearer, maxchan, firm, host, vendor EDB 	if(ver != Version)		myfatal("bad version: got %x expected %x", ver, Version); 	if(srv.start)		myfatal("multiple start messages"); 	srv.start = 1; 	sysname = getenv("sysname");	if(sysname == 0)		strcpy(host, "gnot");	else		strncpy(host, sysname, 64);	free(sysname); 	memset(buf, 0, sizeof(buf)); 	PSHORT(buf+0, sizeof(buf));	/* length */	PSHORT(buf+2, 1);		/* message type */	PLONG(buf+4, Magic);		/* magic */	PSHORT(buf+8, Rstart);		/* op */	PSHORT(buf+12, Version);	/* version */	buf[14] = 1;			/* result = ok */	PLONG(buf+16, Syncframe|Asyncframe);	/* frameing */	PLONG(buf+20, Digital|Analog);	/* berear capabilities */	PSHORT(buf+24, Nchan);		/* max channels */	PSHORT(buf+26, 1);		/* driver version */	PSTRING(buf+28, host, 64);	/* host name */	PSTRING(buf+92, "plan 9", 64);	/* vendor */ 	if(write(1, buf, sizeof(buf)) < sizeof(buf))		myfatal("write failed: %r"); 	return 156;} intsstop(uchar *p, int n){	int reason;	uchar buf[16]; 	if(n < 16)		return 0;	reason = p[12];		SDB "%I: stop %d\n", srv.remote, reason EDB 	memset(buf, 0, sizeof(buf));	PSHORT(buf+0, sizeof(buf));	/* length */	PSHORT(buf+2, 1);		/* message type */	PLONG(buf+4, Magic);		/* magic */	PSHORT(buf+8, Rstop);		/* op */	buf[12] = 1;			/* ok */ 	if(write(1, buf, sizeof(buf)) < sizeof(buf))		myfatal("write failed: %r"); 	return 16;} intsecho(uchar *p, int n){	int id;	uchar buf[20]; 	if(n < 16)		return 0;	id = GLONG(p+12);		SDB "%I: echo %d\n", srv.remote, id EDB 	memset(buf, 0, sizeof(buf));	PSHORT(buf+0, sizeof(buf));	/* length */	PSHORT(buf+2, 1);		/* message type */	PLONG(buf+4, Magic);		/* magic */	PSHORT(buf+8, Recho);		/* op */	PLONG(buf+12, id);		/* id */	p[16] = 1;			/* ok */ 	if(write(1, buf, sizeof(buf)) < sizeof(buf))		myfatal("write failed: %r"); 	return 16;} intscallout(uchar *p, int n){	int id, serial;	int minbps, maxbps, bearer, frame;	int window, delay;	int nphone;	char phone[64], sub[64], buf[32];	Call *c; 	if(n < 168)		return 0; 	if(!srv.start)		myfatal("%I: did not recieve start message", srv.remote);		id = GSHORT(p+12);	serial = GSHORT(p+14);	minbps = GLONG(p+16);	maxbps = GLONG(p+20);	bearer = GLONG(p+24);	frame = GLONG(p+28);	window = GSHORT(p+32);	delay = GSHORT(p+34);	nphone = GSHORT(p+36);	GSTRING(phone, p+40, 64);	GSTRING(sub, p+104, 64); 	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",		srv.remote, id, serial, minbps, maxbps, bearer, frame, window, delay, nphone, phone, sub EDB 	c = callalloc(id);	c->sendwindow = window;	c->delay = delay;	c->pac = 1;	c->recvwindow = srv.recvwindow; 	memset(buf, 0, sizeof(buf));	PSHORT(buf+0, sizeof(buf));	/* length */	PSHORT(buf+2, 1);		/* message type */	PLONG(buf+4, Magic);		/* magic */	PSHORT(buf+8, Rcallout);	/* op */	PSHORT(buf+12, id);		/* call id */	PSHORT(buf+14, id);		/* peer id */	buf[16] = 1;			/* ok */	PLONG(buf+20, 10000000);	/* speed */	PSHORT(buf+24, c->recvwindow);	/* window size */	PSHORT(buf+26, 0);		/* delay */	PLONG(buf+28, 0);		/* channel id */	

Lines 1–500 of 1350.