xref: /plan9/sys/src/cmd/ip/ppp/ppp.c (revision 4f81ea256c7fac55da779894b772fbf5203568fa)
1225077b0SDavid du Colombier /*
2225077b0SDavid du Colombier  * ppp - point-to-point protocol, rfc1331
3225077b0SDavid du Colombier  */
47dd7cddfSDavid du Colombier #include <u.h>
57dd7cddfSDavid du Colombier #include <libc.h>
67dd7cddfSDavid du Colombier #include <auth.h>
77dd7cddfSDavid du Colombier #include <bio.h>
87dd7cddfSDavid du Colombier #include <ip.h>
97dd7cddfSDavid du Colombier #include <libsec.h>
107dd7cddfSDavid du Colombier #include <ndb.h>
117dd7cddfSDavid du Colombier #include "ppp.h"
127dd7cddfSDavid du Colombier 
139a747e4fSDavid du Colombier #define PATH 128
149a747e4fSDavid du Colombier 
157dd7cddfSDavid du Colombier static	int	baud;
167dd7cddfSDavid du Colombier static	int	nocompress;
179a747e4fSDavid du Colombier static 	int	pppframing = 1;
187dd7cddfSDavid du Colombier static	int	noipcompress;
197dd7cddfSDavid du Colombier static	int	server;
20*4f81ea25SDavid du Colombier static	int noauth;
217dd7cddfSDavid du Colombier static	int	nip;		/* number of ip interfaces */
227dd7cddfSDavid du Colombier static	int	dying;		/* flag to signal to all threads its time to go */
2359cc4ca5SDavid du Colombier static	int	primary;	/* this is the primary IP interface */
243ff48bf5SDavid du Colombier static	char	*chatfile;
257dd7cddfSDavid du Colombier 
269a747e4fSDavid du Colombier int	debug;
277dd7cddfSDavid du Colombier char*	LOG = "ppp";
28bedadc12SDavid du Colombier char*	keyspec = "";
297dd7cddfSDavid du Colombier 
307dd7cddfSDavid du Colombier enum
317dd7cddfSDavid du Colombier {
327dd7cddfSDavid du Colombier 	Rmagic=	0x12345
337dd7cddfSDavid du Colombier };
347dd7cddfSDavid du Colombier 
357dd7cddfSDavid du Colombier /*
367dd7cddfSDavid du Colombier  * Calculate FCS - rfc 1331
377dd7cddfSDavid du Colombier  */
387dd7cddfSDavid du Colombier ushort fcstab[256] =
397dd7cddfSDavid du Colombier {
407dd7cddfSDavid du Colombier       0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
417dd7cddfSDavid du Colombier       0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
427dd7cddfSDavid du Colombier       0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
437dd7cddfSDavid du Colombier       0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
447dd7cddfSDavid du Colombier       0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
457dd7cddfSDavid du Colombier       0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
467dd7cddfSDavid du Colombier       0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
477dd7cddfSDavid du Colombier       0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
487dd7cddfSDavid du Colombier       0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
497dd7cddfSDavid du Colombier       0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
507dd7cddfSDavid du Colombier       0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
517dd7cddfSDavid du Colombier       0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
527dd7cddfSDavid du Colombier       0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
537dd7cddfSDavid du Colombier       0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
547dd7cddfSDavid du Colombier       0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
557dd7cddfSDavid du Colombier       0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
567dd7cddfSDavid du Colombier       0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
577dd7cddfSDavid du Colombier       0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
587dd7cddfSDavid du Colombier       0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
597dd7cddfSDavid du Colombier       0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
607dd7cddfSDavid du Colombier       0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
617dd7cddfSDavid du Colombier       0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
627dd7cddfSDavid du Colombier       0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
637dd7cddfSDavid du Colombier       0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
647dd7cddfSDavid du Colombier       0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
657dd7cddfSDavid du Colombier       0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
667dd7cddfSDavid du Colombier       0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
677dd7cddfSDavid du Colombier       0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
687dd7cddfSDavid du Colombier       0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
697dd7cddfSDavid du Colombier       0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
707dd7cddfSDavid du Colombier       0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
717dd7cddfSDavid du Colombier       0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
727dd7cddfSDavid du Colombier };
737dd7cddfSDavid du Colombier 
747dd7cddfSDavid du Colombier static char *snames[] =
757dd7cddfSDavid du Colombier {
767dd7cddfSDavid du Colombier 	"Sclosed",
777dd7cddfSDavid du Colombier 	"Sclosing",
787dd7cddfSDavid du Colombier 	"Sreqsent",
797dd7cddfSDavid du Colombier 	"Sackrcvd",
807dd7cddfSDavid du Colombier 	"Sacksent",
817dd7cddfSDavid du Colombier 	"Sopened",
827dd7cddfSDavid du Colombier };
837dd7cddfSDavid du Colombier 
8480ee5cbfSDavid du Colombier static	void		authtimer(PPP*);
8580ee5cbfSDavid du Colombier static	void		chapinit(PPP*);
8680ee5cbfSDavid du Colombier static	void		config(PPP*, Pstate*, int);
8780ee5cbfSDavid du Colombier static	uchar*		escapeuchar(PPP*, ulong, uchar*, ushort*);
8880ee5cbfSDavid du Colombier static	void		getchap(PPP*, Block*);
8980ee5cbfSDavid du Colombier static	Block*		getframe(PPP*, int*);
9080ee5cbfSDavid du Colombier static	void		getlqm(PPP*, Block*);
9180ee5cbfSDavid du Colombier static	int		getopts(PPP*, Pstate*, Block*);
9280ee5cbfSDavid du Colombier static	void		getpap(PPP*, Block*);
937dd7cddfSDavid du Colombier static	void		init(PPP*);
9480ee5cbfSDavid du Colombier static	void		invalidate(Ipaddr);
957dd7cddfSDavid du Colombier static	void		ipinproc(PPP*);
9680ee5cbfSDavid du Colombier static	char*		ipopen(PPP*);
977dd7cddfSDavid du Colombier static	void		mediainproc(PPP*);
9880ee5cbfSDavid du Colombier static	void		newstate(PPP*, Pstate*, int);
9980ee5cbfSDavid du Colombier static	int		nipifcs(char*);
10080ee5cbfSDavid du Colombier static	void		papinit(PPP*);
1017dd7cddfSDavid du Colombier static	void		pinit(PPP*, Pstate*);
1027dd7cddfSDavid du Colombier static	void		ppptimer(PPP*);
1037dd7cddfSDavid du Colombier static	void		printopts(Pstate*, Block*, int);
10480ee5cbfSDavid du Colombier static	void		ptimer(PPP*, Pstate*);
10580ee5cbfSDavid du Colombier static	int		putframe(PPP*, int, Block*);
10680ee5cbfSDavid du Colombier static	void		putlqm(PPP*);
1077dd7cddfSDavid du Colombier static	void		putndb(PPP*, char*);
10880ee5cbfSDavid du Colombier static	void		putpaprequest(PPP*);
10980ee5cbfSDavid du Colombier static	void		rcv(PPP*, Pstate*, Block*);
11080ee5cbfSDavid du Colombier static	void		rejopts(PPP*, Pstate*, Block*, int);
11180ee5cbfSDavid du Colombier static	void		sendechoreq(PPP*, Pstate*);
11280ee5cbfSDavid du Colombier static	void		sendtermreq(PPP*, Pstate*);
11380ee5cbfSDavid du Colombier static	void		setphase(PPP*, int);
11480ee5cbfSDavid du Colombier static	void		terminate(PPP*, int);
11580ee5cbfSDavid du Colombier static	int		validv4(Ipaddr);
116bedadc12SDavid du Colombier static  void		dmppkt(char *s, uchar *a, int na);
117dc5a79c1SDavid du Colombier static	void		getauth(PPP*);
1187dd7cddfSDavid du Colombier 
1197dd7cddfSDavid du Colombier void
pppopen(PPP * ppp,int mediain,int mediaout,char * net,Ipaddr ipaddr,Ipaddr remip,int mtu,int framing)120d9306527SDavid du Colombier pppopen(PPP *ppp, int mediain, int mediaout, char *net,
1217dd7cddfSDavid du Colombier 	Ipaddr ipaddr, Ipaddr remip,
122bedadc12SDavid du Colombier 	int mtu, int framing)
1237dd7cddfSDavid du Colombier {
1247dd7cddfSDavid du Colombier 	ppp->ipfd = -1;
1257dd7cddfSDavid du Colombier 	ppp->ipcfd = -1;
1267dd7cddfSDavid du Colombier 	invalidate(ppp->remote);
1277dd7cddfSDavid du Colombier 	invalidate(ppp->local);
1286b6b9ac8SDavid du Colombier 	invalidate(ppp->curremote);
1296b6b9ac8SDavid du Colombier 	invalidate(ppp->curlocal);
1307dd7cddfSDavid du Colombier 	invalidate(ppp->dns[0]);
1317dd7cddfSDavid du Colombier 	invalidate(ppp->dns[1]);
1327dd7cddfSDavid du Colombier 	invalidate(ppp->wins[0]);
1337dd7cddfSDavid du Colombier 	invalidate(ppp->wins[1]);
1347dd7cddfSDavid du Colombier 
135d9306527SDavid du Colombier 	ppp->mediain = mediain;
136d9306527SDavid du Colombier 	ppp->mediaout = mediaout;
1377dd7cddfSDavid du Colombier 	if(validv4(remip)){
1387dd7cddfSDavid du Colombier 		ipmove(ppp->remote, remip);
1397dd7cddfSDavid du Colombier 		ppp->remotefrozen = 1;
1407dd7cddfSDavid du Colombier 	}
1417dd7cddfSDavid du Colombier 	if(validv4(ipaddr)){
1427dd7cddfSDavid du Colombier 		ipmove(ppp->local, ipaddr);
1437dd7cddfSDavid du Colombier 		ppp->localfrozen = 1;
1447dd7cddfSDavid du Colombier 	}
1457dd7cddfSDavid du Colombier 	ppp->mtu = Defmtu;
1467dd7cddfSDavid du Colombier 	ppp->mru = mtu;
1477dd7cddfSDavid du Colombier 	ppp->framing = framing;
1487dd7cddfSDavid du Colombier 	ppp->net = net;
149bedadc12SDavid du Colombier 
1507dd7cddfSDavid du Colombier 	init(ppp);
1517dd7cddfSDavid du Colombier 	switch(rfork(RFPROC|RFMEM|RFNOWAIT)){
1527dd7cddfSDavid du Colombier 	case -1:
1537dd7cddfSDavid du Colombier 		sysfatal("forking mediainproc");
1547dd7cddfSDavid du Colombier 	case 0:
1557dd7cddfSDavid du Colombier 		mediainproc(ppp);
1567dd7cddfSDavid du Colombier 		terminate(ppp, 1);
1577dd7cddfSDavid du Colombier 		_exits(0);
1587dd7cddfSDavid du Colombier 	}
1597dd7cddfSDavid du Colombier }
1607dd7cddfSDavid du Colombier 
1617dd7cddfSDavid du Colombier static void
init(PPP * ppp)1627dd7cddfSDavid du Colombier init(PPP* ppp)
1637dd7cddfSDavid du Colombier {
1647dd7cddfSDavid du Colombier 	if(ppp->inbuf == nil){
1657dd7cddfSDavid du Colombier 		ppp->inbuf = allocb(4096);
1667dd7cddfSDavid du Colombier 		if(ppp->inbuf == nil)
1677dd7cddfSDavid du Colombier 			abort();
1687dd7cddfSDavid du Colombier 
1697dd7cddfSDavid du Colombier 		ppp->outbuf = allocb(4096);
1707dd7cddfSDavid du Colombier 		if(ppp->outbuf == nil)
1717dd7cddfSDavid du Colombier 			abort();
1727dd7cddfSDavid du Colombier 
1737dd7cddfSDavid du Colombier 		ppp->lcp = mallocz(sizeof(*ppp->lcp), 1);
1747dd7cddfSDavid du Colombier 		if(ppp->lcp == nil)
1757dd7cddfSDavid du Colombier 			abort();
1767dd7cddfSDavid du Colombier 		ppp->lcp->proto = Plcp;
1777dd7cddfSDavid du Colombier 		ppp->lcp->state = Sclosed;
1787dd7cddfSDavid du Colombier 
1797dd7cddfSDavid du Colombier 		ppp->ccp = mallocz(sizeof(*ppp->ccp), 1);
1807dd7cddfSDavid du Colombier 		if(ppp->ccp == nil)
1817dd7cddfSDavid du Colombier 			abort();
1827dd7cddfSDavid du Colombier 		ppp->ccp->proto = Pccp;
1837dd7cddfSDavid du Colombier 		ppp->ccp->state = Sclosed;
1847dd7cddfSDavid du Colombier 
1857dd7cddfSDavid du Colombier 		ppp->ipcp = mallocz(sizeof(*ppp->ipcp), 1);
1867dd7cddfSDavid du Colombier 		if(ppp->ipcp == nil)
1877dd7cddfSDavid du Colombier 			abort();
1887dd7cddfSDavid du Colombier 		ppp->ipcp->proto = Pipcp;
1897dd7cddfSDavid du Colombier 		ppp->ipcp->state = Sclosed;
1907dd7cddfSDavid du Colombier 
1917dd7cddfSDavid du Colombier 		ppp->chap = mallocz(sizeof(*ppp->chap), 1);
1927dd7cddfSDavid du Colombier 		if(ppp->chap == nil)
1937dd7cddfSDavid du Colombier 			abort();
1947dd7cddfSDavid du Colombier 		ppp->chap->proto = APmschap;
1957dd7cddfSDavid du Colombier 		ppp->chap->state = Cunauth;
1969a747e4fSDavid du Colombier 		auth_freechal(ppp->chap->cs);
1979a747e4fSDavid du Colombier 		ppp->chap->cs = nil;
1987dd7cddfSDavid du Colombier 
1997dd7cddfSDavid du Colombier 		switch(rfork(RFPROC|RFMEM|RFNOWAIT)){
2007dd7cddfSDavid du Colombier 		case -1:
2017dd7cddfSDavid du Colombier 			sysfatal("forking ppptimer");
2027dd7cddfSDavid du Colombier 		case 0:
2037dd7cddfSDavid du Colombier 			ppptimer(ppp);
2047dd7cddfSDavid du Colombier 			_exits(0);
2057dd7cddfSDavid du Colombier 		}
2067dd7cddfSDavid du Colombier 	}
2077dd7cddfSDavid du Colombier 
2087dd7cddfSDavid du Colombier 	ppp->ctcp = compress_init(ppp->ctcp);
2097dd7cddfSDavid du Colombier 	pinit(ppp, ppp->lcp);
2107dd7cddfSDavid du Colombier 	setphase(ppp, Plink);
2117dd7cddfSDavid du Colombier }
2127dd7cddfSDavid du Colombier 
2137dd7cddfSDavid du Colombier static void
setphase(PPP * ppp,int phase)2147dd7cddfSDavid du Colombier setphase(PPP *ppp, int phase)
2157dd7cddfSDavid du Colombier {
2167dd7cddfSDavid du Colombier 	int oldphase;
2177dd7cddfSDavid du Colombier 
2187dd7cddfSDavid du Colombier 	oldphase = ppp->phase;
2197dd7cddfSDavid du Colombier 
2207dd7cddfSDavid du Colombier 	ppp->phase = phase;
2217dd7cddfSDavid du Colombier 	switch(phase){
2227dd7cddfSDavid du Colombier 	default:
2237dd7cddfSDavid du Colombier 		sysfatal("ppp: unknown phase %d", phase);
2247dd7cddfSDavid du Colombier 	case Pdead:
2257dd7cddfSDavid du Colombier 		/* restart or exit? */
2267dd7cddfSDavid du Colombier 		pinit(ppp, ppp->lcp);
2277dd7cddfSDavid du Colombier 		setphase(ppp, Plink);
2287dd7cddfSDavid du Colombier 		break;
2297dd7cddfSDavid du Colombier 	case Plink:
2307dd7cddfSDavid du Colombier 		/* link down */
2317dd7cddfSDavid du Colombier 		switch(oldphase) {
2327dd7cddfSDavid du Colombier 		case Pauth:
2339a747e4fSDavid du Colombier 			auth_freechal(ppp->chap->cs);
2349a747e4fSDavid du Colombier 			ppp->chap->cs = nil;
2357dd7cddfSDavid du Colombier 			ppp->chap->state = Cunauth;
2367dd7cddfSDavid du Colombier 			break;
2377dd7cddfSDavid du Colombier 		case Pnet:
2389a747e4fSDavid du Colombier 			auth_freechal(ppp->chap->cs);
2399a747e4fSDavid du Colombier 			ppp->chap->cs = nil;
2407dd7cddfSDavid du Colombier 			ppp->chap->state = Cunauth;
2417dd7cddfSDavid du Colombier 			newstate(ppp, ppp->ccp, Sclosed);
2427dd7cddfSDavid du Colombier 			newstate(ppp, ppp->ipcp, Sclosed);
2437dd7cddfSDavid du Colombier 		}
2447dd7cddfSDavid du Colombier 		break;
2457dd7cddfSDavid du Colombier 	case Pauth:
2467dd7cddfSDavid du Colombier 		if(server)
2477dd7cddfSDavid du Colombier 			chapinit(ppp);
24880ee5cbfSDavid du Colombier 		else if(ppp->chap->proto == APpasswd)
24980ee5cbfSDavid du Colombier 			papinit(ppp);
2507dd7cddfSDavid du Colombier 		else
2517dd7cddfSDavid du Colombier 			setphase(ppp, Pnet);
2527dd7cddfSDavid du Colombier 		break;
2537dd7cddfSDavid du Colombier 	case Pnet:
2547dd7cddfSDavid du Colombier 		pinit(ppp, ppp->ccp);
2557dd7cddfSDavid du Colombier 		pinit(ppp, ppp->ipcp);
2567dd7cddfSDavid du Colombier 		break;
2577dd7cddfSDavid du Colombier 	case Pterm:
2587dd7cddfSDavid du Colombier 		/* what? */
2597dd7cddfSDavid du Colombier 		break;
2607dd7cddfSDavid du Colombier 	}
2617dd7cddfSDavid du Colombier }
2627dd7cddfSDavid du Colombier 
2637dd7cddfSDavid du Colombier static void
pinit(PPP * ppp,Pstate * p)2647dd7cddfSDavid du Colombier pinit(PPP *ppp, Pstate *p)
2657dd7cddfSDavid du Colombier {
2667dd7cddfSDavid du Colombier 	p->timeout = 0;
2677dd7cddfSDavid du Colombier 
2687dd7cddfSDavid du Colombier 	switch(p->proto){
2697dd7cddfSDavid du Colombier 	case Plcp:
2706b6b9ac8SDavid du Colombier 		ppp->magic = truerand();
2717dd7cddfSDavid du Colombier 		ppp->xctlmap = 0xffffffff;
2727dd7cddfSDavid du Colombier 		ppp->period = 0;
2737dd7cddfSDavid du Colombier 		p->optmask = 0xffffffff;
2747dd7cddfSDavid du Colombier 		if(!server)
2756b6b9ac8SDavid du Colombier 			p->optmask &=  ~(Fauth|Fmtu);
2767dd7cddfSDavid du Colombier 		ppp->rctlmap = 0;
2777dd7cddfSDavid du Colombier 		ppp->ipcp->state = Sclosed;
2787dd7cddfSDavid du Colombier 		ppp->ipcp->optmask = 0xffffffff;
2797dd7cddfSDavid du Colombier 
2807dd7cddfSDavid du Colombier 		p->echotimeout = 0;
2817dd7cddfSDavid du Colombier 
2827dd7cddfSDavid du Colombier 		/* quality goo */
2837dd7cddfSDavid du Colombier 		ppp->timeout = 0;
2847dd7cddfSDavid du Colombier 		memset(&ppp->in, 0, sizeof(ppp->in));
2857dd7cddfSDavid du Colombier 		memset(&ppp->out, 0, sizeof(ppp->out));
2867dd7cddfSDavid du Colombier 		memset(&ppp->pin, 0, sizeof(ppp->pin));
2877dd7cddfSDavid du Colombier 		memset(&ppp->pout, 0, sizeof(ppp->pout));
2887dd7cddfSDavid du Colombier 		memset(&ppp->sin, 0, sizeof(ppp->sin));
2897dd7cddfSDavid du Colombier 		break;
2907dd7cddfSDavid du Colombier 	case Pccp:
2917dd7cddfSDavid du Colombier 		if(nocompress)
2927dd7cddfSDavid du Colombier 			p->optmask = 0;
2937dd7cddfSDavid du Colombier 		else
2947dd7cddfSDavid du Colombier 			p->optmask = Fcmppc;
2957dd7cddfSDavid du Colombier 
29659cc4ca5SDavid du Colombier 		if(ppp->ctype != nil)
2977dd7cddfSDavid du Colombier 			(*ppp->ctype->fini)(ppp->cstate);
2987dd7cddfSDavid du Colombier 		ppp->ctype = nil;
2997dd7cddfSDavid du Colombier 		ppp->ctries = 0;
3007dd7cddfSDavid du Colombier 		ppp->cstate = nil;
3017dd7cddfSDavid du Colombier 
3027dd7cddfSDavid du Colombier 		if(ppp->unctype)
3037dd7cddfSDavid du Colombier 			(*ppp->unctype->fini)(ppp->uncstate);
3047dd7cddfSDavid du Colombier 		ppp->unctype = nil;
3057dd7cddfSDavid du Colombier 		ppp->uncstate = nil;
3067dd7cddfSDavid du Colombier 		break;
3077dd7cddfSDavid du Colombier 	case Pipcp:
3087dd7cddfSDavid du Colombier 		p->optmask = 0xffffffff;
3097dd7cddfSDavid du Colombier 		ppp->ctcp = compress_init(ppp->ctcp);
3107dd7cddfSDavid du Colombier 		break;
3117dd7cddfSDavid du Colombier 	}
3127dd7cddfSDavid du Colombier 	p->confid = p->rcvdconfid = -1;
3137dd7cddfSDavid du Colombier 	config(ppp, p, 1);
3147dd7cddfSDavid du Colombier 	newstate(ppp, p, Sreqsent);
3157dd7cddfSDavid du Colombier }
3167dd7cddfSDavid du Colombier 
3177dd7cddfSDavid du Colombier /*
3187dd7cddfSDavid du Colombier  *  change protocol to a new state.
3197dd7cddfSDavid du Colombier  */
3207dd7cddfSDavid du Colombier static void
newstate(PPP * ppp,Pstate * p,int state)3217dd7cddfSDavid du Colombier newstate(PPP *ppp, Pstate *p, int state)
3227dd7cddfSDavid du Colombier {
3237dd7cddfSDavid du Colombier 	char *err;
3247dd7cddfSDavid du Colombier 
32559cc4ca5SDavid du Colombier 	netlog("ppp: %ux %s->%s ctlmap %lux/%lux flags %lux mtu %ld mru %ld\n",
3267dd7cddfSDavid du Colombier 		p->proto, snames[p->state], snames[state], ppp->rctlmap,
3277dd7cddfSDavid du Colombier 		ppp->xctlmap, p->flags,
3287dd7cddfSDavid du Colombier 		ppp->mtu, ppp->mru);
3296b6b9ac8SDavid du Colombier 	syslog(0, "ppp", "%ux %s->%s ctlmap %lux/%lux flags %lux mtu %ld mru %ld",
3306b6b9ac8SDavid du Colombier 		p->proto, snames[p->state], snames[state], ppp->rctlmap,
3316b6b9ac8SDavid du Colombier 		ppp->xctlmap, p->flags,
3326b6b9ac8SDavid du Colombier 		ppp->mtu, ppp->mru);
3337dd7cddfSDavid du Colombier 
3347dd7cddfSDavid du Colombier 	if(p->proto == Plcp) {
3357dd7cddfSDavid du Colombier 		if(state == Sopened)
336*4f81ea25SDavid du Colombier 			setphase(ppp, noauth? Pnet : Pauth);
3377dd7cddfSDavid du Colombier 		else if(state == Sclosed)
3387dd7cddfSDavid du Colombier 			setphase(ppp, Pdead);
3397dd7cddfSDavid du Colombier 		else if(p->state == Sopened)
3407dd7cddfSDavid du Colombier 			setphase(ppp, Plink);
3417dd7cddfSDavid du Colombier 	}
3427dd7cddfSDavid du Colombier 
3437dd7cddfSDavid du Colombier 	if(p->proto == Pccp && state == Sopened) {
3447dd7cddfSDavid du Colombier 		if(ppp->unctype)
3457dd7cddfSDavid du Colombier 			(*ppp->unctype->fini)(ppp->uncstate);
3467dd7cddfSDavid du Colombier 		ppp->unctype = nil;
3477dd7cddfSDavid du Colombier 		ppp->uncstate = nil;
3487dd7cddfSDavid du Colombier 		if(p->optmask & Fcmppc) {
3497dd7cddfSDavid du Colombier 			ppp->unctype = &uncmppc;
3507dd7cddfSDavid du Colombier 			ppp->uncstate = (*uncmppc.init)(ppp);
3517dd7cddfSDavid du Colombier 		}
3527dd7cddfSDavid du Colombier 		if(p->optmask & Fcthwack){
3537dd7cddfSDavid du Colombier 			ppp->unctype = &uncthwack;
3547dd7cddfSDavid du Colombier 			ppp->uncstate = (*uncthwack.init)(ppp);
3557dd7cddfSDavid du Colombier 		}
3567dd7cddfSDavid du Colombier 	}
3577dd7cddfSDavid du Colombier 
3587dd7cddfSDavid du Colombier 	if(p->proto == Pipcp && state == Sopened) {
359*4f81ea25SDavid du Colombier 		if(server && !noauth && ppp->chap->state != Cauthok)
3607dd7cddfSDavid du Colombier 			abort();
3617dd7cddfSDavid du Colombier 
3627dd7cddfSDavid du Colombier 		err = ipopen(ppp);
3637dd7cddfSDavid du Colombier 		if(err != nil)
3647dd7cddfSDavid du Colombier 			sysfatal("%s", err);
3657dd7cddfSDavid du Colombier 	}
3667dd7cddfSDavid du Colombier 
3677dd7cddfSDavid du Colombier 	p->state = state;
3687dd7cddfSDavid du Colombier }
3697dd7cddfSDavid du Colombier 
3707dd7cddfSDavid du Colombier /* returns (protocol, information) */
3717dd7cddfSDavid du Colombier static Block*
getframe(PPP * ppp,int * protop)3727dd7cddfSDavid du Colombier getframe(PPP *ppp, int *protop)
3737dd7cddfSDavid du Colombier {
3747dd7cddfSDavid du Colombier 	uchar *p, *from, *to;
3757dd7cddfSDavid du Colombier 	int n, len, proto;
3767dd7cddfSDavid du Colombier 	ulong c;
3777dd7cddfSDavid du Colombier 	ushort fcs;
3787dd7cddfSDavid du Colombier 	Block *buf, *b;
3797dd7cddfSDavid du Colombier 
3807dd7cddfSDavid du Colombier 	*protop = 0;
3817dd7cddfSDavid du Colombier 	if(ppp->framing == 0) {
3827dd7cddfSDavid du Colombier 		/* assume data is already framed */
3837dd7cddfSDavid du Colombier 		b = allocb(2000);
3847dd7cddfSDavid du Colombier 		len = b->lim - b->wptr;
385d9306527SDavid du Colombier 		n = read(ppp->mediain, b->wptr, len);
386bedadc12SDavid du Colombier  		dmppkt("RX", b->wptr, n);
3877dd7cddfSDavid du Colombier 		if(n <= 0 || n == len){
3887dd7cddfSDavid du Colombier 			freeb(b);
3897dd7cddfSDavid du Colombier 
3907dd7cddfSDavid du Colombier 			return nil;
3917dd7cddfSDavid du Colombier 		}
3927dd7cddfSDavid du Colombier 		b->wptr += n;
3937dd7cddfSDavid du Colombier 
3947dd7cddfSDavid du Colombier 		/* should probably copy to another block if small */
3957dd7cddfSDavid du Colombier 
3969a747e4fSDavid du Colombier 		if(pppframing && b->rptr[0] == PPP_addr && b->rptr[1] == PPP_ctl)
3977dd7cddfSDavid du Colombier 			b->rptr += 2;
3987dd7cddfSDavid du Colombier 		proto = *b->rptr++;
3997dd7cddfSDavid du Colombier 		if((proto & 0x1) == 0)
4007dd7cddfSDavid du Colombier 			proto = (proto<<8) | *b->rptr++;
4017dd7cddfSDavid du Colombier 
4027dd7cddfSDavid du Colombier 		if(b->rptr >= b->wptr){
4037dd7cddfSDavid du Colombier 			freeb(b);
4047dd7cddfSDavid du Colombier 			return nil;
4057dd7cddfSDavid du Colombier 		}
4067dd7cddfSDavid du Colombier 
4077dd7cddfSDavid du Colombier 		ppp->in.uchars += n;
4087dd7cddfSDavid du Colombier 		ppp->in.packets++;
4097dd7cddfSDavid du Colombier 		*protop = proto;
4109a747e4fSDavid du Colombier 		netlog("getframe 0x%x\n", proto);
4117dd7cddfSDavid du Colombier 		return b;
4127dd7cddfSDavid du Colombier 	}
4137dd7cddfSDavid du Colombier 
4147dd7cddfSDavid du Colombier 	buf = ppp->inbuf;
4157dd7cddfSDavid du Colombier 	for(;;){
4167dd7cddfSDavid du Colombier 		/* read till we hit a frame uchar or run out of room */
4177dd7cddfSDavid du Colombier 		for(p = buf->rptr; buf->wptr < buf->lim;){
4187dd7cddfSDavid du Colombier 			for(; p < buf->wptr; p++)
4197dd7cddfSDavid du Colombier 				if(*p == HDLC_frame)
4207dd7cddfSDavid du Colombier 					break;
4217dd7cddfSDavid du Colombier 			if(p != buf->wptr)
4227dd7cddfSDavid du Colombier 				break;
4237dd7cddfSDavid du Colombier 
4247dd7cddfSDavid du Colombier 			len = buf->lim - buf->wptr;
425d9306527SDavid du Colombier 			n = read(ppp->mediain, buf->wptr, len);
4267dd7cddfSDavid du Colombier 			if(n <= 0){
4279a747e4fSDavid du Colombier 				syslog(0, LOG, "medium read returns %d: %r", n);
4287dd7cddfSDavid du Colombier 				buf->wptr = buf->rptr;
4297dd7cddfSDavid du Colombier 				return nil;
4307dd7cddfSDavid du Colombier 			}
431bedadc12SDavid du Colombier  			dmppkt("RX", buf->wptr, n);
4327dd7cddfSDavid du Colombier 			buf->wptr += n;
4337dd7cddfSDavid du Colombier 		}
4347dd7cddfSDavid du Colombier 
4357dd7cddfSDavid du Colombier 		/* copy into block, undoing escapes, and caculating fcs */
4367dd7cddfSDavid du Colombier 		fcs = PPP_initfcs;
4377dd7cddfSDavid du Colombier 		b = allocb(p - buf->rptr);
4387dd7cddfSDavid du Colombier 		to = b->wptr;
4397dd7cddfSDavid du Colombier 		for(from = buf->rptr; from != p;){
4407dd7cddfSDavid du Colombier 			c = *from++;
4417dd7cddfSDavid du Colombier 			if(c == HDLC_esc){
4427dd7cddfSDavid du Colombier 				if(from == p)
4437dd7cddfSDavid du Colombier 					break;
4447dd7cddfSDavid du Colombier 				c = *from++ ^ 0x20;
4457dd7cddfSDavid du Colombier 			} else if((c < 0x20) && (ppp->rctlmap & (1 << c)))
4467dd7cddfSDavid du Colombier 				continue;
4477dd7cddfSDavid du Colombier 			*to++ = c;
4487dd7cddfSDavid du Colombier 			fcs = (fcs >> 8) ^ fcstab[(fcs ^ c) & 0xff];
4497dd7cddfSDavid du Colombier 		}
4507dd7cddfSDavid du Colombier 
4517dd7cddfSDavid du Colombier 		/* copy down what's left in buffer */
4527dd7cddfSDavid du Colombier 		p++;
4537dd7cddfSDavid du Colombier 		memmove(buf->rptr, p, buf->wptr - p);
4547dd7cddfSDavid du Colombier 		n = p - buf->rptr;
4557dd7cddfSDavid du Colombier 		buf->wptr -= n;
4567dd7cddfSDavid du Colombier 		b->wptr = to - 2;
4577dd7cddfSDavid du Colombier 
4587dd7cddfSDavid du Colombier 		/* return to caller if checksum matches */
4597dd7cddfSDavid du Colombier 		if(fcs == PPP_goodfcs){
4607dd7cddfSDavid du Colombier 			if(b->rptr[0] == PPP_addr && b->rptr[1] == PPP_ctl)
4617dd7cddfSDavid du Colombier 				b->rptr += 2;
4627dd7cddfSDavid du Colombier 			proto = *b->rptr++;
4637dd7cddfSDavid du Colombier 			if((proto & 0x1) == 0)
4647dd7cddfSDavid du Colombier 				proto = (proto<<8) | *b->rptr++;
4657dd7cddfSDavid du Colombier 			if(b->rptr < b->wptr){
4667dd7cddfSDavid du Colombier 				ppp->in.uchars += n;
4677dd7cddfSDavid du Colombier 				ppp->in.packets++;
4687dd7cddfSDavid du Colombier 				*protop = proto;
4699a747e4fSDavid du Colombier 				netlog("getframe 0x%x\n", proto);
4707dd7cddfSDavid du Colombier 				return b;
4717dd7cddfSDavid du Colombier 			}
4727dd7cddfSDavid du Colombier 		} else if(BLEN(b) > 0){
473fe853e23SDavid du Colombier 			if(ppp->ctcp)
474fe853e23SDavid du Colombier 				compress_error(ppp->ctcp);
4757dd7cddfSDavid du Colombier 			ppp->in.discards++;
47639734e7eSDavid du Colombier 			netlog("ppp: discard len %ld/%ld cksum %ux (%ux %ux %ux %ux)\n",
4777dd7cddfSDavid du Colombier 				BLEN(b), BLEN(buf), fcs, b->rptr[0],
4787dd7cddfSDavid du Colombier 				b->rptr[1], b->rptr[2], b->rptr[3]);
4797dd7cddfSDavid du Colombier 		}
4807dd7cddfSDavid du Colombier 
4817dd7cddfSDavid du Colombier 		freeb(b);
4827dd7cddfSDavid du Colombier 	}
4837dd7cddfSDavid du Colombier }
4847dd7cddfSDavid du Colombier 
4857dd7cddfSDavid du Colombier /* send a PPP frame */
4867dd7cddfSDavid du Colombier static int
putframe(PPP * ppp,int proto,Block * b)4877dd7cddfSDavid du Colombier putframe(PPP *ppp, int proto, Block *b)
4887dd7cddfSDavid du Colombier {
4897dd7cddfSDavid du Colombier 	Block *buf;
4907dd7cddfSDavid du Colombier 	uchar *to, *from;
4917dd7cddfSDavid du Colombier 	ushort fcs;
4927dd7cddfSDavid du Colombier 	ulong ctlmap;
4937dd7cddfSDavid du Colombier 	uchar c;
4947dd7cddfSDavid du Colombier 	Block *bp;
4957dd7cddfSDavid du Colombier 
4967dd7cddfSDavid du Colombier 	ppp->out.packets++;
4977dd7cddfSDavid du Colombier 
4987dd7cddfSDavid du Colombier 	if(proto == Plcp)
4997dd7cddfSDavid du Colombier 		ctlmap = 0xffffffff;
5007dd7cddfSDavid du Colombier 	else
5017dd7cddfSDavid du Colombier 		ctlmap = ppp->xctlmap;
5027dd7cddfSDavid du Colombier 
5037dd7cddfSDavid du Colombier 	/* make sure we have head room */
5047dd7cddfSDavid du Colombier 	if(b->rptr - b->base < 4){
5057dd7cddfSDavid du Colombier 		b = padb(b, 4);
5067dd7cddfSDavid du Colombier 		b->rptr += 4;
5077dd7cddfSDavid du Colombier 	}
5087dd7cddfSDavid du Colombier 
5096b6b9ac8SDavid du Colombier 	netlog("ppp: putframe 0x%ux %ld\n", proto, b->wptr-b->rptr);
5106b6b9ac8SDavid du Colombier 
51159cc4ca5SDavid du Colombier 	/* add in the protocol and address, we'd better have left room */
5127dd7cddfSDavid du Colombier 	from = b->rptr;
5137dd7cddfSDavid du Colombier 	*--from = proto;
5147dd7cddfSDavid du Colombier 	if(!(ppp->lcp->flags&Fpc) || proto > 0x100 || proto == Plcp)
5157dd7cddfSDavid du Colombier 		*--from = proto>>8;
5169a747e4fSDavid du Colombier 	if(pppframing && (!(ppp->lcp->flags&Fac) || proto == Plcp)){
5177dd7cddfSDavid du Colombier 		*--from = PPP_ctl;
5187dd7cddfSDavid du Colombier 		*--from = PPP_addr;
5197dd7cddfSDavid du Colombier 	}
5207dd7cddfSDavid du Colombier 
5217dd7cddfSDavid du Colombier 	qlock(&ppp->outlock);
5227dd7cddfSDavid du Colombier 	buf = ppp->outbuf;
5237dd7cddfSDavid du Colombier 
5247dd7cddfSDavid du Colombier 	if(ppp->framing == 0) {
5257dd7cddfSDavid du Colombier 		to = buf->rptr;
5267dd7cddfSDavid du Colombier 		for(bp = b; bp; bp = bp->next){
5277dd7cddfSDavid du Colombier 			if(bp != b)
5287dd7cddfSDavid du Colombier 				from = bp->rptr;
5297dd7cddfSDavid du Colombier 			memmove(to, from, bp->wptr-from);
5307dd7cddfSDavid du Colombier 			to += bp->wptr-from;
5317dd7cddfSDavid du Colombier 		}
5327dd7cddfSDavid du Colombier 	} else {
5337dd7cddfSDavid du Colombier 		/* escape and checksum the body */
5347dd7cddfSDavid du Colombier 		fcs = PPP_initfcs;
5357dd7cddfSDavid du Colombier 		to = buf->rptr;
5366b6b9ac8SDavid du Colombier 
5376b6b9ac8SDavid du Colombier 		/* add frame marker */
5386b6b9ac8SDavid du Colombier 		*to++ = HDLC_frame;
5396b6b9ac8SDavid du Colombier 
5407dd7cddfSDavid du Colombier 		for(bp = b; bp; bp = bp->next){
5417dd7cddfSDavid du Colombier 			if(bp != b)
5427dd7cddfSDavid du Colombier 				from = bp->rptr;
5437dd7cddfSDavid du Colombier 			for(; from < bp->wptr; from++){
5447dd7cddfSDavid du Colombier 				c = *from;
5457dd7cddfSDavid du Colombier 				if(c == HDLC_frame || c == HDLC_esc
5467dd7cddfSDavid du Colombier 				   || (c < 0x20 && ((1<<c) & ctlmap))){
5477dd7cddfSDavid du Colombier 					*to++ = HDLC_esc;
5487dd7cddfSDavid du Colombier 					*to++ = c ^ 0x20;
5497dd7cddfSDavid du Colombier 				} else
5507dd7cddfSDavid du Colombier 					*to++ = c;
5517dd7cddfSDavid du Colombier 				fcs = (fcs >> 8) ^ fcstab[(fcs ^ c) & 0xff];
5527dd7cddfSDavid du Colombier 			}
5537dd7cddfSDavid du Colombier 		}
5547dd7cddfSDavid du Colombier 
5557dd7cddfSDavid du Colombier 		/* add on and escape the checksum */
5567dd7cddfSDavid du Colombier 		fcs = ~fcs;
5577dd7cddfSDavid du Colombier 		c = fcs;
5587dd7cddfSDavid du Colombier 		if(c == HDLC_frame || c == HDLC_esc
5597dd7cddfSDavid du Colombier 		   || (c < 0x20 && ((1<<c) & ctlmap))){
5607dd7cddfSDavid du Colombier 			*to++ = HDLC_esc;
5617dd7cddfSDavid du Colombier 			*to++ = c ^ 0x20;
5627dd7cddfSDavid du Colombier 		} else
5637dd7cddfSDavid du Colombier 			*to++ = c;
5647dd7cddfSDavid du Colombier 		c = fcs>>8;
5657dd7cddfSDavid du Colombier 		if(c == HDLC_frame || c == HDLC_esc
5667dd7cddfSDavid du Colombier 		   || (c < 0x20 && ((1<<c) & ctlmap))){
5677dd7cddfSDavid du Colombier 			*to++ = HDLC_esc;
5687dd7cddfSDavid du Colombier 			*to++ = c ^ 0x20;
5697dd7cddfSDavid du Colombier 		} else
5707dd7cddfSDavid du Colombier 			*to++ = c;
5717dd7cddfSDavid du Colombier 
5727dd7cddfSDavid du Colombier 		/* add frame marker */
5737dd7cddfSDavid du Colombier 		*to++ = HDLC_frame;
5747dd7cddfSDavid du Colombier 	}
5757dd7cddfSDavid du Colombier 
5767dd7cddfSDavid du Colombier 	/* send */
5777dd7cddfSDavid du Colombier 	buf->wptr = to;
578bedadc12SDavid du Colombier  	dmppkt("TX", buf->rptr, BLEN(buf));
579d9306527SDavid du Colombier 	if(write(ppp->mediaout, buf->rptr, BLEN(buf)) < 0){
5807dd7cddfSDavid du Colombier 		qunlock(&ppp->outlock);
5817dd7cddfSDavid du Colombier 		return -1;
5827dd7cddfSDavid du Colombier 	}
5837dd7cddfSDavid du Colombier 	ppp->out.uchars += BLEN(buf);
5847dd7cddfSDavid du Colombier 
5857dd7cddfSDavid du Colombier 	qunlock(&ppp->outlock);
5867dd7cddfSDavid du Colombier 	return 0;
5877dd7cddfSDavid du Colombier }
5887dd7cddfSDavid du Colombier 
5897dd7cddfSDavid du Colombier Block*
alloclcp(int code,int id,int len,Lcpmsg ** mp)5907dd7cddfSDavid du Colombier alloclcp(int code, int id, int len, Lcpmsg **mp)
5917dd7cddfSDavid du Colombier {
5927dd7cddfSDavid du Colombier 	Block *b;
5937dd7cddfSDavid du Colombier 	Lcpmsg *m;
5947dd7cddfSDavid du Colombier 
5957dd7cddfSDavid du Colombier 	/*
5967dd7cddfSDavid du Colombier 	 *  leave room for header
5977dd7cddfSDavid du Colombier 	 */
5987dd7cddfSDavid du Colombier 	b = allocb(len);
5997dd7cddfSDavid du Colombier 
6007dd7cddfSDavid du Colombier 	m = (Lcpmsg*)b->wptr;
6017dd7cddfSDavid du Colombier 	m->code = code;
6027dd7cddfSDavid du Colombier 	m->id = id;
6037dd7cddfSDavid du Colombier 	b->wptr += 4;
6047dd7cddfSDavid du Colombier 
6057dd7cddfSDavid du Colombier 	*mp = m;
6067dd7cddfSDavid du Colombier 	return b;
6077dd7cddfSDavid du Colombier }
6087dd7cddfSDavid du Colombier 
6097dd7cddfSDavid du Colombier 
6107dd7cddfSDavid du Colombier static void
putlo(Block * b,int type,ulong val)6117dd7cddfSDavid du Colombier putlo(Block *b, int type, ulong val)
6127dd7cddfSDavid du Colombier {
6137dd7cddfSDavid du Colombier 	*b->wptr++ = type;
6147dd7cddfSDavid du Colombier 	*b->wptr++ = 6;
6157dd7cddfSDavid du Colombier 	hnputl(b->wptr, val);
6167dd7cddfSDavid du Colombier 	b->wptr += 4;
6177dd7cddfSDavid du Colombier }
6187dd7cddfSDavid du Colombier 
6197dd7cddfSDavid du Colombier static void
putv4o(Block * b,int type,Ipaddr val)6207dd7cddfSDavid du Colombier putv4o(Block *b, int type, Ipaddr val)
6217dd7cddfSDavid du Colombier {
6227dd7cddfSDavid du Colombier 	*b->wptr++ = type;
6237dd7cddfSDavid du Colombier 	*b->wptr++ = 6;
6247dd7cddfSDavid du Colombier 	v6tov4(b->wptr, val);
6257dd7cddfSDavid du Colombier 	b->wptr += 4;
6267dd7cddfSDavid du Colombier }
6277dd7cddfSDavid du Colombier 
6287dd7cddfSDavid du Colombier static void
putso(Block * b,int type,ulong val)6297dd7cddfSDavid du Colombier putso(Block *b, int type, ulong val)
6307dd7cddfSDavid du Colombier {
6317dd7cddfSDavid du Colombier 	*b->wptr++ = type;
6327dd7cddfSDavid du Colombier 	*b->wptr++ = 4;
6337dd7cddfSDavid du Colombier 	hnputs(b->wptr, val);
6347dd7cddfSDavid du Colombier 	b->wptr += 2;
6357dd7cddfSDavid du Colombier }
6367dd7cddfSDavid du Colombier 
6377dd7cddfSDavid du Colombier static void
puto(Block * b,int type)6387dd7cddfSDavid du Colombier puto(Block *b, int type)
6397dd7cddfSDavid du Colombier {
6407dd7cddfSDavid du Colombier 	*b->wptr++ = type;
6417dd7cddfSDavid du Colombier 	*b->wptr++ = 2;
6427dd7cddfSDavid du Colombier }
6437dd7cddfSDavid du Colombier 
6447dd7cddfSDavid du Colombier /*
6457dd7cddfSDavid du Colombier  *  send configuration request
6467dd7cddfSDavid du Colombier  */
6477dd7cddfSDavid du Colombier static void
config(PPP * ppp,Pstate * p,int newid)6487dd7cddfSDavid du Colombier config(PPP *ppp, Pstate *p, int newid)
6497dd7cddfSDavid du Colombier {
6507dd7cddfSDavid du Colombier 	Block *b;
6517dd7cddfSDavid du Colombier 	Lcpmsg *m;
6527dd7cddfSDavid du Colombier 	int id;
6537dd7cddfSDavid du Colombier 
6547dd7cddfSDavid du Colombier 	if(newid){
6556b6b9ac8SDavid du Colombier 		id = p->id++;
6567dd7cddfSDavid du Colombier 		p->confid = id;
6577dd7cddfSDavid du Colombier 		p->timeout = Timeout;
6587dd7cddfSDavid du Colombier 	} else
6597dd7cddfSDavid du Colombier 		id = p->confid;
6607dd7cddfSDavid du Colombier 	b = alloclcp(Lconfreq, id, 256, &m);
6617dd7cddfSDavid du Colombier 	USED(m);
6627dd7cddfSDavid du Colombier 
6637dd7cddfSDavid du Colombier 	switch(p->proto){
6647dd7cddfSDavid du Colombier 	case Plcp:
6656b6b9ac8SDavid du Colombier 		if(p->optmask & Fctlmap)
6666b6b9ac8SDavid du Colombier 			putlo(b, Octlmap, 0);	/* we don't want anything escaped */
6677dd7cddfSDavid du Colombier 		if(p->optmask & Fmagic)
6687dd7cddfSDavid du Colombier 			putlo(b, Omagic, ppp->magic);
6697dd7cddfSDavid du Colombier 		if(p->optmask & Fmtu)
6707dd7cddfSDavid du Colombier 			putso(b, Omtu, ppp->mru);
6717dd7cddfSDavid du Colombier 		if(p->optmask & Fauth) {
6727dd7cddfSDavid du Colombier 			*b->wptr++ = Oauth;
6737dd7cddfSDavid du Colombier 			*b->wptr++ = 5;
6747dd7cddfSDavid du Colombier 			hnputs(b->wptr, Pchap);
6757dd7cddfSDavid du Colombier 			b->wptr += 2;
6767dd7cddfSDavid du Colombier 			*b->wptr++ = ppp->chap->proto;
6777dd7cddfSDavid du Colombier 		}
6787dd7cddfSDavid du Colombier 		if(p->optmask & Fpc)
6797dd7cddfSDavid du Colombier 			puto(b, Opc);
6806b6b9ac8SDavid du Colombier 		if(p->optmask & Fac)
6816b6b9ac8SDavid du Colombier 			puto(b, Oac);
6827dd7cddfSDavid du Colombier 		break;
6837dd7cddfSDavid du Colombier 	case Pccp:
68459cc4ca5SDavid du Colombier 		if(p->optmask & Fcthwack)
68559cc4ca5SDavid du Colombier 			puto(b, Octhwack);
68659cc4ca5SDavid du Colombier 		else if(p->optmask & Fcmppc) {
6877dd7cddfSDavid du Colombier 			*b->wptr++ = Ocmppc;
6887dd7cddfSDavid du Colombier 			*b->wptr++ = 6;
6897dd7cddfSDavid du Colombier 			*b->wptr++ = 0;
6907dd7cddfSDavid du Colombier 			*b->wptr++ = 0;
6917dd7cddfSDavid du Colombier 			*b->wptr++ = 0;
6927dd7cddfSDavid du Colombier 			*b->wptr++ = 0x41;
6937dd7cddfSDavid du Colombier 		}
6947dd7cddfSDavid du Colombier 		break;
6957dd7cddfSDavid du Colombier 	case Pipcp:
6967dd7cddfSDavid du Colombier 		if(p->optmask & Fipaddr)
6976b6b9ac8SDavid du Colombier {syslog(0, "ppp", "requesting %I", ppp->local);
6987dd7cddfSDavid du Colombier 			putv4o(b, Oipaddr, ppp->local);
6996b6b9ac8SDavid du Colombier }
700bedadc12SDavid du Colombier 		if(primary && (p->optmask & Fipdns))
701bedadc12SDavid du Colombier 			putv4o(b, Oipdns, ppp->dns[0]);
702bedadc12SDavid du Colombier 		if(primary && (p->optmask & Fipdns2))
703bedadc12SDavid du Colombier 			putv4o(b, Oipdns2, ppp->dns[1]);
704bedadc12SDavid du Colombier 		if(primary && (p->optmask & Fipwins))
705bedadc12SDavid du Colombier 			putv4o(b, Oipwins, ppp->wins[0]);
706bedadc12SDavid du Colombier 		if(primary && (p->optmask & Fipwins2))
707bedadc12SDavid du Colombier 			putv4o(b, Oipwins2, ppp->wins[1]);
70859cc4ca5SDavid du Colombier 		/*
70959cc4ca5SDavid du Colombier 		 * don't ask for header compression while data compression is still pending.
71059cc4ca5SDavid du Colombier 		 * perhaps we should restart ipcp negotiation if compression negotiation fails.
71159cc4ca5SDavid du Colombier 		 */
71259cc4ca5SDavid du Colombier 		if(!noipcompress && !ppp->ccp->optmask && (p->optmask & Fipcompress)) {
7137dd7cddfSDavid du Colombier 			*b->wptr++ = Oipcompress;
7147dd7cddfSDavid du Colombier 			*b->wptr++ = 6;
7157dd7cddfSDavid du Colombier 			hnputs(b->wptr, Pvjctcp);
7167dd7cddfSDavid du Colombier 			b->wptr += 2;
7177dd7cddfSDavid du Colombier 			*b->wptr++ = MAX_STATES-1;
7187dd7cddfSDavid du Colombier 			*b->wptr++ = 1;
7197dd7cddfSDavid du Colombier 		}
7207dd7cddfSDavid du Colombier 		break;
7217dd7cddfSDavid du Colombier 	}
7227dd7cddfSDavid du Colombier 	hnputs(m->len, BLEN(b));
7237dd7cddfSDavid du Colombier 	printopts(p, b, 1);
7247dd7cddfSDavid du Colombier 	putframe(ppp, p->proto, b);
7257dd7cddfSDavid du Colombier 	freeb(b);
7267dd7cddfSDavid du Colombier }
7277dd7cddfSDavid du Colombier 
7287dd7cddfSDavid du Colombier static void
getipinfo(PPP * ppp)7297dd7cddfSDavid du Colombier getipinfo(PPP *ppp)
7307dd7cddfSDavid du Colombier {
7317dd7cddfSDavid du Colombier 	char *av[3];
7327dd7cddfSDavid du Colombier 	int ndns, nwins;
7337dd7cddfSDavid du Colombier 	char ip[64];
7347dd7cddfSDavid du Colombier 	Ndbtuple *t, *nt;
7357dd7cddfSDavid du Colombier 
7367dd7cddfSDavid du Colombier 	if(!validv4(ppp->local))
7377dd7cddfSDavid du Colombier 		return;
7387dd7cddfSDavid du Colombier 
7397dd7cddfSDavid du Colombier 	av[0] = "dns";
7407dd7cddfSDavid du Colombier 	av[1] = "wins";
7417dd7cddfSDavid du Colombier 	sprint(ip, "%I", ppp->local);
7427dd7cddfSDavid du Colombier 	t = csipinfo(ppp->net, "ip", ip, av, 2);
7437dd7cddfSDavid du Colombier 	ndns = nwins = 0;
7447dd7cddfSDavid du Colombier 	for(nt = t; nt != nil; nt = nt->entry){
7457dd7cddfSDavid du Colombier 		if(strcmp(nt->attr, "dns") == 0){
7467dd7cddfSDavid du Colombier 			if(ndns < 2)
7477dd7cddfSDavid du Colombier 				parseip(ppp->dns[ndns++], nt->val);
7487dd7cddfSDavid du Colombier 		} else if(strcmp(nt->attr, "wins") == 0){
7497dd7cddfSDavid du Colombier 			if(nwins < 2)
7507dd7cddfSDavid du Colombier 				parseip(ppp->wins[nwins++], nt->val);
7517dd7cddfSDavid du Colombier 		}
7527dd7cddfSDavid du Colombier 	}
7537dd7cddfSDavid du Colombier 	if(t != nil)
7547dd7cddfSDavid du Colombier 		ndbfree(t);
7557dd7cddfSDavid du Colombier }
7567dd7cddfSDavid du Colombier 
7577dd7cddfSDavid du Colombier /*
7587dd7cddfSDavid du Colombier  *  parse configuration request, sends an ack or reject packet
7597dd7cddfSDavid du Colombier  *
7607dd7cddfSDavid du Colombier  *	returns:	-1 if request was syntacticly incorrect
7617dd7cddfSDavid du Colombier  *			 0 if packet was accepted
7627dd7cddfSDavid du Colombier  *			 1 if packet was rejected
7637dd7cddfSDavid du Colombier  */
7647dd7cddfSDavid du Colombier static int
getopts(PPP * ppp,Pstate * p,Block * b)7657dd7cddfSDavid du Colombier getopts(PPP *ppp, Pstate *p, Block *b)
7667dd7cddfSDavid du Colombier {
7677dd7cddfSDavid du Colombier 	Lcpmsg *m, *repm;
7687dd7cddfSDavid du Colombier 	Lcpopt *o;
7697dd7cddfSDavid du Colombier 	uchar *cp, *ap;
7709a747e4fSDavid du Colombier 	ulong rejecting, nacking, flags, proto, chapproto;
7717dd7cddfSDavid du Colombier 	ulong mtu, ctlmap, period;
7727dd7cddfSDavid du Colombier 	ulong x;
7737dd7cddfSDavid du Colombier 	Block *repb;
7747dd7cddfSDavid du Colombier 	Comptype *ctype;
7757dd7cddfSDavid du Colombier 	Ipaddr ipaddr;
7767dd7cddfSDavid du Colombier 
7777dd7cddfSDavid du Colombier 	rejecting = 0;
7787dd7cddfSDavid du Colombier 	nacking = 0;
7797dd7cddfSDavid du Colombier 	flags = 0;
7807dd7cddfSDavid du Colombier 
7817dd7cddfSDavid du Colombier 	/* defaults */
7827dd7cddfSDavid du Colombier 	invalidate(ipaddr);
7837dd7cddfSDavid du Colombier 	mtu = ppp->mtu;
7847dd7cddfSDavid du Colombier 	ctlmap = 0xffffffff;
7857dd7cddfSDavid du Colombier 	period = 0;
7867dd7cddfSDavid du Colombier 	ctype = nil;
7879a747e4fSDavid du Colombier 	chapproto = 0;
7887dd7cddfSDavid du Colombier 
7897dd7cddfSDavid du Colombier 	m = (Lcpmsg*)b->rptr;
7907dd7cddfSDavid du Colombier 	repb = alloclcp(Lconfack, m->id, BLEN(b), &repm);
7917dd7cddfSDavid du Colombier 
7927dd7cddfSDavid du Colombier 	/* copy options into ack packet */
7937dd7cddfSDavid du Colombier 	memmove(repm->data, m->data, b->wptr - m->data);
7947dd7cddfSDavid du Colombier 	repb->wptr += b->wptr - m->data;
7957dd7cddfSDavid du Colombier 
7967dd7cddfSDavid du Colombier 	/* look for options we don't recognize or like */
7977dd7cddfSDavid du Colombier 	for(cp = m->data; cp < b->wptr; cp += o->len){
7987dd7cddfSDavid du Colombier 		o = (Lcpopt*)cp;
7997dd7cddfSDavid du Colombier 		if(cp + o->len > b->wptr || o->len==0){
8007dd7cddfSDavid du Colombier 			freeb(repb);
8017dd7cddfSDavid du Colombier 			netlog("ppp: bad option length %ux\n", o->type);
8027dd7cddfSDavid du Colombier 			return -1;
8037dd7cddfSDavid du Colombier 		}
8047dd7cddfSDavid du Colombier 
8057dd7cddfSDavid du Colombier 		switch(p->proto){
8067dd7cddfSDavid du Colombier 		case Plcp:
8077dd7cddfSDavid du Colombier 			switch(o->type){
8087dd7cddfSDavid du Colombier 			case Oac:
8097dd7cddfSDavid du Colombier 				flags |= Fac;
8107dd7cddfSDavid du Colombier 				continue;
8117dd7cddfSDavid du Colombier 			case Opc:
8127dd7cddfSDavid du Colombier 				flags |= Fpc;
8137dd7cddfSDavid du Colombier 				continue;
8147dd7cddfSDavid du Colombier 			case Omtu:
8157dd7cddfSDavid du Colombier 				mtu = nhgets(o->data);
8167dd7cddfSDavid du Colombier 				continue;
8177dd7cddfSDavid du Colombier 			case Omagic:
8187dd7cddfSDavid du Colombier 				if(ppp->magic == nhgetl(o->data))
8197dd7cddfSDavid du Colombier 					netlog("ppp: possible loop\n");
8207dd7cddfSDavid du Colombier 				continue;
8217dd7cddfSDavid du Colombier 			case Octlmap:
8227dd7cddfSDavid du Colombier 				ctlmap = nhgetl(o->data);
8237dd7cddfSDavid du Colombier 				continue;
8247dd7cddfSDavid du Colombier 			case Oquality:
8257dd7cddfSDavid du Colombier 				proto = nhgets(o->data);
8267dd7cddfSDavid du Colombier 				if(proto != Plqm)
8277dd7cddfSDavid du Colombier 					break;
8287dd7cddfSDavid du Colombier 				x = nhgetl(o->data+2)*10;
8297dd7cddfSDavid du Colombier 				period = (x+Period-1)/Period;
8307dd7cddfSDavid du Colombier 				continue;
8317dd7cddfSDavid du Colombier 			case Oauth:
8327dd7cddfSDavid du Colombier 				proto = nhgets(o->data);
83380ee5cbfSDavid du Colombier 				if(proto == Ppasswd && !server){
8349a747e4fSDavid du Colombier 					chapproto = APpasswd;
83580ee5cbfSDavid du Colombier 					continue;
83680ee5cbfSDavid du Colombier 				}
8377dd7cddfSDavid du Colombier 				if(proto != Pchap)
8387dd7cddfSDavid du Colombier 					break;
8399a747e4fSDavid du Colombier 				if(o->data[2] != APmd5 && o->data[2] != APmschap)
8407dd7cddfSDavid du Colombier 					break;
8419a747e4fSDavid du Colombier 				chapproto = o->data[2];
8427dd7cddfSDavid du Colombier 				continue;
8437dd7cddfSDavid du Colombier 			}
8447dd7cddfSDavid du Colombier 			break;
8457dd7cddfSDavid du Colombier 		case Pccp:
8467dd7cddfSDavid du Colombier 			if(nocompress)
8477dd7cddfSDavid du Colombier 				break;
8487dd7cddfSDavid du Colombier 			switch(o->type){
8497dd7cddfSDavid du Colombier 			case Octhwack:
8507dd7cddfSDavid du Colombier 				break;
851b85a8364SDavid du Colombier 			/*
8527dd7cddfSDavid du Colombier 				if(o->len == 2){
8537dd7cddfSDavid du Colombier 					ctype = &cthwack;
8547dd7cddfSDavid du Colombier 					continue;
8557dd7cddfSDavid du Colombier 				}
8567dd7cddfSDavid du Colombier 				if(!nacking){
8577dd7cddfSDavid du Colombier 					nacking = 1;
8587dd7cddfSDavid du Colombier 					repb->wptr = repm->data;
8597dd7cddfSDavid du Colombier 					repm->code = Lconfnak;
8607dd7cddfSDavid du Colombier 				}
86159cc4ca5SDavid du Colombier 				puto(repb, Octhwack);
8627dd7cddfSDavid du Colombier 				continue;
863b85a8364SDavid du Colombier 			*/
8647dd7cddfSDavid du Colombier 			case Ocmppc:
8657dd7cddfSDavid du Colombier 				x = nhgetl(o->data);
8667dd7cddfSDavid du Colombier 
8677dd7cddfSDavid du Colombier 				// hack for Mac
8687dd7cddfSDavid du Colombier 				// if(x == 0)
8697dd7cddfSDavid du Colombier 				//	continue;
8707dd7cddfSDavid du Colombier 
8717dd7cddfSDavid du Colombier 				/* stop ppp loops */
8727dd7cddfSDavid du Colombier 				if((x&0x41) == 0 || ppp->ctries++ > 5) {
8737dd7cddfSDavid du Colombier 					/*
8747dd7cddfSDavid du Colombier 					 * turn off requests as well - I don't think this
8757dd7cddfSDavid du Colombier 					 * is needed in the standard
8767dd7cddfSDavid du Colombier 					 */
8777dd7cddfSDavid du Colombier 					p->optmask &= ~Fcmppc;
8787dd7cddfSDavid du Colombier 					break;
8797dd7cddfSDavid du Colombier 				}
8807dd7cddfSDavid du Colombier 				if(rejecting)
8817dd7cddfSDavid du Colombier 					continue;
882bedadc12SDavid du Colombier 				if(x & 1) {
8837dd7cddfSDavid du Colombier 					ctype = &cmppc;
8847dd7cddfSDavid du Colombier 					ppp->sendencrypted = (o->data[3]&0x40) == 0x40;
8857dd7cddfSDavid du Colombier 					continue;
8867dd7cddfSDavid du Colombier 				}
8877dd7cddfSDavid du Colombier 				if(!nacking){
8887dd7cddfSDavid du Colombier 					nacking = 1;
8897dd7cddfSDavid du Colombier 					repb->wptr = repm->data;
8907dd7cddfSDavid du Colombier 					repm->code = Lconfnak;
8917dd7cddfSDavid du Colombier 				}
8927dd7cddfSDavid du Colombier 				*repb->wptr++ = Ocmppc;
8937dd7cddfSDavid du Colombier 				*repb->wptr++ = 6;
8947dd7cddfSDavid du Colombier 				*repb->wptr++ = 0;
8957dd7cddfSDavid du Colombier 				*repb->wptr++ = 0;
8967dd7cddfSDavid du Colombier 				*repb->wptr++ = 0;
8977dd7cddfSDavid du Colombier 				*repb->wptr++ = 0x41;
8987dd7cddfSDavid du Colombier 				continue;
8997dd7cddfSDavid du Colombier 			}
9007dd7cddfSDavid du Colombier 			break;
9017dd7cddfSDavid du Colombier 		case Pipcp:
9027dd7cddfSDavid du Colombier 			switch(o->type){
9037dd7cddfSDavid du Colombier 			case Oipaddr:
9047dd7cddfSDavid du Colombier 				v4tov6(ipaddr, o->data);
9057dd7cddfSDavid du Colombier 				if(!validv4(ppp->remote))
9067dd7cddfSDavid du Colombier 					continue;
9077dd7cddfSDavid du Colombier 				if(!validv4(ipaddr) && !rejecting){
9087dd7cddfSDavid du Colombier 					/* other side requesting an address */
9097dd7cddfSDavid du Colombier 					if(!nacking){
9107dd7cddfSDavid du Colombier 						nacking = 1;
9117dd7cddfSDavid du Colombier 						repb->wptr = repm->data;
9127dd7cddfSDavid du Colombier 						repm->code = Lconfnak;
9137dd7cddfSDavid du Colombier 					}
9147dd7cddfSDavid du Colombier 					putv4o(repb, Oipaddr, ppp->remote);
9157dd7cddfSDavid du Colombier 				}
9167dd7cddfSDavid du Colombier 				continue;
9177dd7cddfSDavid du Colombier 			case Oipdns:
9187dd7cddfSDavid du Colombier 				ap = ppp->dns[0];
9197dd7cddfSDavid du Colombier 				goto ipinfo;
9207dd7cddfSDavid du Colombier 			case Oipdns2:
9217dd7cddfSDavid du Colombier 				ap = ppp->dns[1];
9227dd7cddfSDavid du Colombier 				goto ipinfo;
9237dd7cddfSDavid du Colombier 			case Oipwins:
9247dd7cddfSDavid du Colombier 				ap = ppp->wins[0];
9257dd7cddfSDavid du Colombier 				goto ipinfo;
9267dd7cddfSDavid du Colombier 			case Oipwins2:
9277dd7cddfSDavid du Colombier 				ap = ppp->wins[1];
9287dd7cddfSDavid du Colombier 				goto ipinfo;
9297dd7cddfSDavid du Colombier 			ipinfo:
9307dd7cddfSDavid du Colombier 				if(!validv4(ap))
9317dd7cddfSDavid du Colombier 					getipinfo(ppp);
9327dd7cddfSDavid du Colombier 				if(!validv4(ap))
9337dd7cddfSDavid du Colombier 					break;
9347dd7cddfSDavid du Colombier 				v4tov6(ipaddr, o->data);
9357dd7cddfSDavid du Colombier 				if(!validv4(ipaddr) && !rejecting){
9367dd7cddfSDavid du Colombier 					/* other side requesting an address */
9377dd7cddfSDavid du Colombier 					if(!nacking){
9387dd7cddfSDavid du Colombier 						nacking = 1;
9397dd7cddfSDavid du Colombier 						repb->wptr = repm->data;
9407dd7cddfSDavid du Colombier 						repm->code = Lconfnak;
9417dd7cddfSDavid du Colombier 					}
9427dd7cddfSDavid du Colombier 					putv4o(repb, o->type, ap);
9437dd7cddfSDavid du Colombier 				}
9447dd7cddfSDavid du Colombier 				continue;
9457dd7cddfSDavid du Colombier 			case Oipcompress:
94659cc4ca5SDavid du Colombier 				/*
94759cc4ca5SDavid du Colombier 				 * don't compress tcp header if we've negotiated data compression.
94859cc4ca5SDavid du Colombier 				 * tcp header compression has very poor performance if there is an error.
94959cc4ca5SDavid du Colombier 				 */
9507dd7cddfSDavid du Colombier 				proto = nhgets(o->data);
95159cc4ca5SDavid du Colombier 				if(noipcompress || proto != Pvjctcp || ppp->ctype != nil)
9527dd7cddfSDavid du Colombier 					break;
9537dd7cddfSDavid du Colombier 				if(compress_negotiate(ppp->ctcp, o->data+2) < 0)
9547dd7cddfSDavid du Colombier 					break;
9557dd7cddfSDavid du Colombier 				flags |= Fipcompress;
9567dd7cddfSDavid du Colombier 				continue;
9577dd7cddfSDavid du Colombier 			}
9587dd7cddfSDavid du Colombier 			break;
9597dd7cddfSDavid du Colombier 		}
9607dd7cddfSDavid du Colombier 
9617dd7cddfSDavid du Colombier 		/* come here if option is not recognized */
9627dd7cddfSDavid du Colombier 		if(!rejecting){
9637dd7cddfSDavid du Colombier 			rejecting = 1;
9647dd7cddfSDavid du Colombier 			repb->wptr = repm->data;
9657dd7cddfSDavid du Colombier 			repm->code = Lconfrej;
9667dd7cddfSDavid du Colombier 		}
9677dd7cddfSDavid du Colombier 		netlog("ppp: bad %ux option %d\n", p->proto, o->type);
9687dd7cddfSDavid du Colombier 		memmove(repb->wptr, o, o->len);
9697dd7cddfSDavid du Colombier 		repb->wptr += o->len;
9707dd7cddfSDavid du Colombier 	}
9717dd7cddfSDavid du Colombier 
9727dd7cddfSDavid du Colombier 	/* permanent changes only after we know that we liked the packet */
9737dd7cddfSDavid du Colombier 	if(!rejecting && !nacking){
9747dd7cddfSDavid du Colombier 		switch(p->proto){
9757dd7cddfSDavid du Colombier 		case Plcp:
9767dd7cddfSDavid du Colombier 			ppp->period = period;
9777dd7cddfSDavid du Colombier 			ppp->xctlmap = ctlmap;
9787dd7cddfSDavid du Colombier 			if(mtu > Maxmtu)
9797dd7cddfSDavid du Colombier 				mtu = Maxmtu;
9807dd7cddfSDavid du Colombier 			if(mtu < Minmtu)
9817dd7cddfSDavid du Colombier 				mtu = Minmtu;
9827dd7cddfSDavid du Colombier 			ppp->mtu = mtu;
9839a747e4fSDavid du Colombier 			if(chapproto)
9849a747e4fSDavid du Colombier 				ppp->chap->proto = chapproto;
9857dd7cddfSDavid du Colombier 
9867dd7cddfSDavid du Colombier 			break;
9877dd7cddfSDavid du Colombier 		case Pccp:
98859cc4ca5SDavid du Colombier 			if(ppp->ctype != nil){
98959cc4ca5SDavid du Colombier 				(*ppp->ctype->fini)(ppp->cstate);
99059cc4ca5SDavid du Colombier 				ppp->cstate = nil;
99159cc4ca5SDavid du Colombier 			}
9927dd7cddfSDavid du Colombier 			ppp->ctype = ctype;
9937dd7cddfSDavid du Colombier 			if(ctype)
9947dd7cddfSDavid du Colombier 				ppp->cstate = (*ctype->init)(ppp);
9957dd7cddfSDavid du Colombier 			break;
9967dd7cddfSDavid du Colombier 		case Pipcp:
9977dd7cddfSDavid du Colombier 			if(validv4(ipaddr) && ppp->remotefrozen == 0)
9987dd7cddfSDavid du Colombier  				ipmove(ppp->remote, ipaddr);
9997dd7cddfSDavid du Colombier 			break;
10007dd7cddfSDavid du Colombier 		}
100159cc4ca5SDavid du Colombier 		p->flags = flags;
10027dd7cddfSDavid du Colombier 	}
10037dd7cddfSDavid du Colombier 
10047dd7cddfSDavid du Colombier 	hnputs(repm->len, BLEN(repb));
10057dd7cddfSDavid du Colombier 	printopts(p, repb, 1);
10067dd7cddfSDavid du Colombier 	putframe(ppp, p->proto, repb);
10077dd7cddfSDavid du Colombier 	freeb(repb);
10087dd7cddfSDavid du Colombier 
10097dd7cddfSDavid du Colombier 	return rejecting || nacking;
10107dd7cddfSDavid du Colombier }
1011bedadc12SDavid du Colombier static void
dmppkt(char * s,uchar * a,int na)1012bedadc12SDavid du Colombier dmppkt(char *s, uchar *a, int na)
1013bedadc12SDavid du Colombier {
1014bedadc12SDavid du Colombier 	int i;
1015bedadc12SDavid du Colombier 
1016bedadc12SDavid du Colombier 	if (debug < 3)
1017bedadc12SDavid du Colombier 		return;
1018bedadc12SDavid du Colombier 
1019bedadc12SDavid du Colombier 	fprint(2, "%s", s);
1020bedadc12SDavid du Colombier 	for(i = 0; i < na; i++)
1021bedadc12SDavid du Colombier 		fprint(2, " %.2ux", a[i]);
1022bedadc12SDavid du Colombier 	fprint(2, "\n");
1023bedadc12SDavid du Colombier }
10247dd7cddfSDavid du Colombier 
10256b6b9ac8SDavid du Colombier static void
dropoption(Pstate * p,Lcpopt * o)10266b6b9ac8SDavid du Colombier dropoption(Pstate *p, Lcpopt *o)
10276b6b9ac8SDavid du Colombier {
1028bedadc12SDavid du Colombier 	unsigned n = o->type;
1029bedadc12SDavid du Colombier 
1030bedadc12SDavid du Colombier 	switch(n){
103187dfdc75SDavid du Colombier 	case Oipaddr:
103287dfdc75SDavid du Colombier 		break;
1033bedadc12SDavid du Colombier 	case Oipdns:
1034bedadc12SDavid du Colombier 		p->optmask &= ~Fipdns;
1035bedadc12SDavid du Colombier 		break;
1036bedadc12SDavid du Colombier 	case Oipwins:
1037bedadc12SDavid du Colombier 		p->optmask &= ~Fipwins;
1038bedadc12SDavid du Colombier 		break;
1039bedadc12SDavid du Colombier 	case Oipdns2:
1040bedadc12SDavid du Colombier 		p->optmask &= ~Fipdns2;
1041bedadc12SDavid du Colombier 		break;
1042bedadc12SDavid du Colombier 	case Oipwins2:
1043bedadc12SDavid du Colombier 		p->optmask &= ~Fipwins2;
1044bedadc12SDavid du Colombier 		break;
1045bedadc12SDavid du Colombier 	default:
10466b6b9ac8SDavid du Colombier 		if(o->type < 8*sizeof(p->optmask))
10476b6b9ac8SDavid du Colombier 			p->optmask &= ~(1<<o->type);
1048bedadc12SDavid du Colombier 		break;
1049bedadc12SDavid du Colombier 	}
10506b6b9ac8SDavid du Colombier }
10516b6b9ac8SDavid du Colombier 
10527dd7cddfSDavid du Colombier /*
10537dd7cddfSDavid du Colombier  *  parse configuration rejection, just stop sending anything that they
10547dd7cddfSDavid du Colombier  *  don't like (except for ipcp address nak).
10557dd7cddfSDavid du Colombier  */
10567dd7cddfSDavid du Colombier static void
rejopts(PPP * ppp,Pstate * p,Block * b,int code)10577dd7cddfSDavid du Colombier rejopts(PPP *ppp, Pstate *p, Block *b, int code)
10587dd7cddfSDavid du Colombier {
10597dd7cddfSDavid du Colombier 	Lcpmsg *m;
10607dd7cddfSDavid du Colombier 	Lcpopt *o;
10616b6b9ac8SDavid du Colombier 	uchar newip[IPaddrlen];
10627dd7cddfSDavid du Colombier 
10637dd7cddfSDavid du Colombier 	/* just give up trying what the other side doesn't like */
10647dd7cddfSDavid du Colombier 	m = (Lcpmsg*)b->rptr;
10657dd7cddfSDavid du Colombier 	for(b->rptr = m->data; b->rptr < b->wptr; b->rptr += o->len){
10667dd7cddfSDavid du Colombier 		o = (Lcpopt*)b->rptr;
10677dd7cddfSDavid du Colombier 		if(b->rptr + o->len > b->wptr){
10687dd7cddfSDavid du Colombier 			netlog("ppp: bad roption length %ux\n", o->type);
10697dd7cddfSDavid du Colombier 			return;
10707dd7cddfSDavid du Colombier 		}
10717dd7cddfSDavid du Colombier 
10727dd7cddfSDavid du Colombier 		if(code == Lconfrej){
10736b6b9ac8SDavid du Colombier 			dropoption(p, o);
10747dd7cddfSDavid du Colombier 			netlog("ppp: %ux rejecting %d\n",
10757dd7cddfSDavid du Colombier 					p->proto, o->type);
10767dd7cddfSDavid du Colombier 			continue;
10777dd7cddfSDavid du Colombier 		}
10787dd7cddfSDavid du Colombier 
10797dd7cddfSDavid du Colombier 		switch(p->proto){
10807dd7cddfSDavid du Colombier 		case Plcp:
10817dd7cddfSDavid du Colombier 			switch(o->type){
10827dd7cddfSDavid du Colombier 			case Octlmap:
10837dd7cddfSDavid du Colombier 				ppp->rctlmap = nhgetl(o->data);
10847dd7cddfSDavid du Colombier 				break;
10857dd7cddfSDavid du Colombier 			case Oauth:
10867dd7cddfSDavid du Colombier 				/* don't allow client to request no auth */
10877dd7cddfSDavid du Colombier 				/* could try different auth protocol here */
10887dd7cddfSDavid du Colombier 				fprint(2, "ppp: can not reject CHAP\n");
10897dd7cddfSDavid du Colombier 				exits("ppp: CHAP");
10907dd7cddfSDavid du Colombier 				break;
10917dd7cddfSDavid du Colombier 			default:
10927dd7cddfSDavid du Colombier 				if(o->type < 8*sizeof(p->optmask))
10937dd7cddfSDavid du Colombier 					p->optmask &= ~(1<<o->type);
10947dd7cddfSDavid du Colombier 				break;
10957dd7cddfSDavid du Colombier 			};
10967dd7cddfSDavid du Colombier 			break;
10977dd7cddfSDavid du Colombier 		case Pccp:
10987dd7cddfSDavid du Colombier 			switch(o->type){
10997dd7cddfSDavid du Colombier 			default:
11006b6b9ac8SDavid du Colombier 				dropoption(p, o);
11017dd7cddfSDavid du Colombier 				break;
11027dd7cddfSDavid du Colombier 			}
11037dd7cddfSDavid du Colombier 			break;
11047dd7cddfSDavid du Colombier 		case Pipcp:
11057dd7cddfSDavid du Colombier 			switch(o->type){
11067dd7cddfSDavid du Colombier 			case Oipaddr:
11076b6b9ac8SDavid du Colombier syslog(0, "ppp", "rejected addr %I with %V", ppp->local, o->data);
11086b6b9ac8SDavid du Colombier 				/* if we're a server, don't let other end change our addr */
11096b6b9ac8SDavid du Colombier 				if(ppp->localfrozen){
11106b6b9ac8SDavid du Colombier 					dropoption(p, o);
11116b6b9ac8SDavid du Colombier 					break;
11126b6b9ac8SDavid du Colombier 				}
11136b6b9ac8SDavid du Colombier 
11146b6b9ac8SDavid du Colombier 				/* accept whatever server tells us */
11156b6b9ac8SDavid du Colombier 				if(!validv4(ppp->local)){
11166b6b9ac8SDavid du Colombier 					v4tov6(ppp->local, o->data);
11176b6b9ac8SDavid du Colombier 					dropoption(p, o);
11186b6b9ac8SDavid du Colombier 					break;
11196b6b9ac8SDavid du Colombier 				}
11206b6b9ac8SDavid du Colombier 
11216b6b9ac8SDavid du Colombier 				/* if he didn't like our addr, ask for a generic one */
11226b6b9ac8SDavid du Colombier 				v4tov6(newip, o->data);
11236b6b9ac8SDavid du Colombier 				if(!validv4(newip)){
11246b6b9ac8SDavid du Colombier 					invalidate(ppp->local);
11256b6b9ac8SDavid du Colombier 					break;
11266b6b9ac8SDavid du Colombier 				}
11276b6b9ac8SDavid du Colombier 
11286b6b9ac8SDavid du Colombier 				/* if he gives us something different, use it anyways */
11296b6b9ac8SDavid du Colombier 				v4tov6(ppp->local, o->data);
11306b6b9ac8SDavid du Colombier 				dropoption(p, o);
11317dd7cddfSDavid du Colombier 				break;
1132bedadc12SDavid du Colombier 			case Oipdns:
1133bedadc12SDavid du Colombier 				if (!validv4(ppp->dns[0])){
1134bedadc12SDavid du Colombier 					v4tov6(ppp->dns[0], o->data);
1135bedadc12SDavid du Colombier 					dropoption(p, o);
1136bedadc12SDavid du Colombier 					break;
1137bedadc12SDavid du Colombier 				}
1138bedadc12SDavid du Colombier 				v4tov6(newip, o->data);
1139bedadc12SDavid du Colombier 				if(!validv4(newip)){
1140bedadc12SDavid du Colombier 					invalidate(ppp->dns[0]);
1141bedadc12SDavid du Colombier 					break;
1142bedadc12SDavid du Colombier 				}
1143bedadc12SDavid du Colombier 				v4tov6(ppp->dns[0], o->data);
1144bedadc12SDavid du Colombier 				dropoption(p, o);
1145bedadc12SDavid du Colombier 				break;
1146bedadc12SDavid du Colombier 			case Oipwins:
1147bedadc12SDavid du Colombier 				if (!validv4(ppp->wins[0])){
1148bedadc12SDavid du Colombier 					v4tov6(ppp->wins[0], o->data);
1149bedadc12SDavid du Colombier 					dropoption(p, o);
1150bedadc12SDavid du Colombier 					break;
1151bedadc12SDavid du Colombier 				}
1152bedadc12SDavid du Colombier 				v4tov6(newip, o->data);
1153bedadc12SDavid du Colombier 				if(!validv4(newip)){
1154bedadc12SDavid du Colombier 					invalidate(ppp->wins[0]);
1155bedadc12SDavid du Colombier 					break;
1156bedadc12SDavid du Colombier 				}
1157bedadc12SDavid du Colombier 				v4tov6(ppp->wins[0], o->data);
1158bedadc12SDavid du Colombier 				dropoption(p, o);
1159bedadc12SDavid du Colombier 				break;
1160bedadc12SDavid du Colombier 			case Oipdns2:
1161bedadc12SDavid du Colombier 				if (!validv4(ppp->dns[1])){
1162bedadc12SDavid du Colombier 					v4tov6(ppp->dns[1], o->data);
1163bedadc12SDavid du Colombier 					dropoption(p, o);
1164bedadc12SDavid du Colombier 					break;
1165bedadc12SDavid du Colombier 				}
1166bedadc12SDavid du Colombier 				v4tov6(newip, o->data);
1167bedadc12SDavid du Colombier 				if(!validv4(newip)){
1168bedadc12SDavid du Colombier 					invalidate(ppp->dns[1]);
1169bedadc12SDavid du Colombier 					break;
1170bedadc12SDavid du Colombier 				}
1171bedadc12SDavid du Colombier 				v4tov6(ppp->dns[1], o->data);
1172bedadc12SDavid du Colombier 				dropoption(p, o);
1173bedadc12SDavid du Colombier 				break;
1174bedadc12SDavid du Colombier 			case Oipwins2:
1175bedadc12SDavid du Colombier 				if (!validv4(ppp->wins[1])){
1176bedadc12SDavid du Colombier 					v4tov6(ppp->wins[1], o->data);
1177bedadc12SDavid du Colombier 					dropoption(p, o);
1178bedadc12SDavid du Colombier 					break;
1179bedadc12SDavid du Colombier 				}
1180bedadc12SDavid du Colombier 				v4tov6(newip, o->data);
1181bedadc12SDavid du Colombier 				if(!validv4(newip)){
1182bedadc12SDavid du Colombier 					invalidate(ppp->wins[1]);
1183bedadc12SDavid du Colombier 					break;
1184bedadc12SDavid du Colombier 				}
1185bedadc12SDavid du Colombier 				v4tov6(ppp->wins[1], o->data);
1186bedadc12SDavid du Colombier 				dropoption(p, o);
1187bedadc12SDavid du Colombier 				break;
11887dd7cddfSDavid du Colombier 			default:
11896b6b9ac8SDavid du Colombier 				dropoption(p, o);
11907dd7cddfSDavid du Colombier 				break;
11917dd7cddfSDavid du Colombier 			}
11927dd7cddfSDavid du Colombier 			break;
11937dd7cddfSDavid du Colombier 		}
11947dd7cddfSDavid du Colombier 	}
11957dd7cddfSDavid du Colombier }
11967dd7cddfSDavid du Colombier 
11977dd7cddfSDavid du Colombier 
11987dd7cddfSDavid du Colombier /*
11997dd7cddfSDavid du Colombier  *  put a messages through the lcp or ipcp state machine.  They are
12007dd7cddfSDavid du Colombier  *  very similar.
12017dd7cddfSDavid du Colombier  */
12027dd7cddfSDavid du Colombier static void
rcv(PPP * ppp,Pstate * p,Block * b)12037dd7cddfSDavid du Colombier rcv(PPP *ppp, Pstate *p, Block *b)
12047dd7cddfSDavid du Colombier {
12057dd7cddfSDavid du Colombier 	ulong len;
12067dd7cddfSDavid du Colombier 	int err;
12077dd7cddfSDavid du Colombier 	Lcpmsg *m;
12087dd7cddfSDavid du Colombier 	int proto;
12097dd7cddfSDavid du Colombier 
12107dd7cddfSDavid du Colombier 	if(BLEN(b) < 4){
12117dd7cddfSDavid du Colombier 		netlog("ppp: short lcp message\n");
12127dd7cddfSDavid du Colombier 		freeb(b);
12137dd7cddfSDavid du Colombier 		return;
12147dd7cddfSDavid du Colombier 	}
12157dd7cddfSDavid du Colombier 	m = (Lcpmsg*)b->rptr;
12167dd7cddfSDavid du Colombier 	len = nhgets(m->len);
12177dd7cddfSDavid du Colombier 	if(BLEN(b) < len){
12187dd7cddfSDavid du Colombier 		netlog("ppp: short lcp message\n");
12197dd7cddfSDavid du Colombier 		freeb(b);
12207dd7cddfSDavid du Colombier 		return;
12217dd7cddfSDavid du Colombier 	}
12227dd7cddfSDavid du Colombier 
122359cc4ca5SDavid du Colombier 	netlog("ppp: %ux rcv %d len %ld id %d/%d/%d\n",
12247dd7cddfSDavid du Colombier 		p->proto, m->code, len, m->id, p->confid, p->id);
12257dd7cddfSDavid du Colombier 
12267dd7cddfSDavid du Colombier 	if(p->proto != Plcp && ppp->lcp->state != Sopened){
12277dd7cddfSDavid du Colombier 		netlog("ppp: non-lcp with lcp not open\n");
12287dd7cddfSDavid du Colombier 		freeb(b);
12297dd7cddfSDavid du Colombier 		return;
12307dd7cddfSDavid du Colombier 	}
12317dd7cddfSDavid du Colombier 
12327dd7cddfSDavid du Colombier 	qlock(ppp);
12337dd7cddfSDavid du Colombier 	switch(m->code){
12347dd7cddfSDavid du Colombier 	case Lconfreq:
12357dd7cddfSDavid du Colombier 		printopts(p, b, 0);
12367dd7cddfSDavid du Colombier 		err = getopts(ppp, p, b);
12377dd7cddfSDavid du Colombier 		if(err < 0)
12387dd7cddfSDavid du Colombier 			break;
12397dd7cddfSDavid du Colombier 
12407dd7cddfSDavid du Colombier 		if(m->id == p->rcvdconfid)
12417dd7cddfSDavid du Colombier 			break;			/* don't change state for duplicates */
12427dd7cddfSDavid du Colombier 
12437dd7cddfSDavid du Colombier 		switch(p->state){
12447dd7cddfSDavid du Colombier 		case Sackrcvd:
12457dd7cddfSDavid du Colombier 			if(err)
12467dd7cddfSDavid du Colombier 				break;
12477dd7cddfSDavid du Colombier 			newstate(ppp, p, Sopened);
12487dd7cddfSDavid du Colombier 			break;
12497dd7cddfSDavid du Colombier 		case Sclosed:
12507dd7cddfSDavid du Colombier 		case Sopened:
12517dd7cddfSDavid du Colombier 			config(ppp, p, 1);
12527dd7cddfSDavid du Colombier 			if(err == 0)
12537dd7cddfSDavid du Colombier 				newstate(ppp, p, Sacksent);
12547dd7cddfSDavid du Colombier 			else
12557dd7cddfSDavid du Colombier 				newstate(ppp, p, Sreqsent);
12567dd7cddfSDavid du Colombier 			break;
12577dd7cddfSDavid du Colombier 		case Sreqsent:
12587dd7cddfSDavid du Colombier 		case Sacksent:
12597dd7cddfSDavid du Colombier 			if(err == 0)
12607dd7cddfSDavid du Colombier 				newstate(ppp, p, Sacksent);
12617dd7cddfSDavid du Colombier 			else
12627dd7cddfSDavid du Colombier 				newstate(ppp, p, Sreqsent);
12637dd7cddfSDavid du Colombier 			break;
12647dd7cddfSDavid du Colombier 		}
12657dd7cddfSDavid du Colombier 		break;
12667dd7cddfSDavid du Colombier 	case Lconfack:
12677dd7cddfSDavid du Colombier 		if(p->confid != m->id){
12687dd7cddfSDavid du Colombier 			/* ignore if it isn't the message we're sending */
12697dd7cddfSDavid du Colombier 			netlog("ppp: dropping confack\n");
12707dd7cddfSDavid du Colombier 			break;
12717dd7cddfSDavid du Colombier 		}
12727dd7cddfSDavid du Colombier 		p->confid = -1;		/* ignore duplicates */
12737dd7cddfSDavid du Colombier 		p->id++;		/* avoid sending duplicates */
12747dd7cddfSDavid du Colombier 
12757dd7cddfSDavid du Colombier 		netlog("ppp: recv confack\n");
12767dd7cddfSDavid du Colombier 		switch(p->state){
12777dd7cddfSDavid du Colombier 		case Sopened:
12787dd7cddfSDavid du Colombier 		case Sackrcvd:
12797dd7cddfSDavid du Colombier 			config(ppp, p, 1);
12807dd7cddfSDavid du Colombier 			newstate(ppp, p, Sreqsent);
12817dd7cddfSDavid du Colombier 			break;
12827dd7cddfSDavid du Colombier 		case Sreqsent:
12837dd7cddfSDavid du Colombier 			newstate(ppp, p, Sackrcvd);
12847dd7cddfSDavid du Colombier 			break;
12857dd7cddfSDavid du Colombier 		case Sacksent:
12867dd7cddfSDavid du Colombier 			newstate(ppp, p, Sopened);
12877dd7cddfSDavid du Colombier 			break;
12887dd7cddfSDavid du Colombier 		}
12897dd7cddfSDavid du Colombier 		break;
12907dd7cddfSDavid du Colombier 	case Lconfrej:
12917dd7cddfSDavid du Colombier 	case Lconfnak:
12927dd7cddfSDavid du Colombier 		if(p->confid != m->id) {
12937dd7cddfSDavid du Colombier 			/* ignore if it isn't the message we're sending */
12947dd7cddfSDavid du Colombier 			netlog("ppp: dropping confrej or confnak\n");
12957dd7cddfSDavid du Colombier 			break;
12967dd7cddfSDavid du Colombier 		}
12977dd7cddfSDavid du Colombier 		p->confid = -1;		/* ignore duplicates */
12987dd7cddfSDavid du Colombier 		p->id++;		/* avoid sending duplicates */
12997dd7cddfSDavid du Colombier 
13007dd7cddfSDavid du Colombier 		switch(p->state){
13017dd7cddfSDavid du Colombier 		case Sopened:
13027dd7cddfSDavid du Colombier 		case Sackrcvd:
13037dd7cddfSDavid du Colombier 			config(ppp, p, 1);
13047dd7cddfSDavid du Colombier 			newstate(ppp, p, Sreqsent);
13057dd7cddfSDavid du Colombier 			break;
13067dd7cddfSDavid du Colombier 		case Sreqsent:
13077dd7cddfSDavid du Colombier 		case Sacksent:
13087dd7cddfSDavid du Colombier 			printopts(p, b, 0);
13097dd7cddfSDavid du Colombier 			rejopts(ppp, p, b, m->code);
13107dd7cddfSDavid du Colombier 			config(ppp, p, 1);
13117dd7cddfSDavid du Colombier 			break;
13127dd7cddfSDavid du Colombier 		}
13137dd7cddfSDavid du Colombier 		break;
13147dd7cddfSDavid du Colombier 	case Ltermreq:
13157dd7cddfSDavid du Colombier 		m->code = Ltermack;
13167dd7cddfSDavid du Colombier 		putframe(ppp, p->proto, b);
13177dd7cddfSDavid du Colombier 
13187dd7cddfSDavid du Colombier 		switch(p->state){
13197dd7cddfSDavid du Colombier 		case Sackrcvd:
13207dd7cddfSDavid du Colombier 		case Sacksent:
13217dd7cddfSDavid du Colombier 			newstate(ppp, p, Sreqsent);
13227dd7cddfSDavid du Colombier 			break;
13237dd7cddfSDavid du Colombier 		case Sopened:
13247dd7cddfSDavid du Colombier 			newstate(ppp, p, Sclosing);
13257dd7cddfSDavid du Colombier 			break;
13267dd7cddfSDavid du Colombier 		}
13277dd7cddfSDavid du Colombier 		break;
13287dd7cddfSDavid du Colombier 	case Ltermack:
13297dd7cddfSDavid du Colombier 		if(p->termid != m->id)	/* ignore if it isn't the message we're sending */
13307dd7cddfSDavid du Colombier 			break;
13317dd7cddfSDavid du Colombier 
13327dd7cddfSDavid du Colombier 		if(p->proto == Plcp)
13337dd7cddfSDavid du Colombier 			ppp->ipcp->state = Sclosed;
13347dd7cddfSDavid du Colombier 		switch(p->state){
13357dd7cddfSDavid du Colombier 		case Sclosing:
13367dd7cddfSDavid du Colombier 			newstate(ppp, p, Sclosed);
13377dd7cddfSDavid du Colombier 			break;
13387dd7cddfSDavid du Colombier 		case Sackrcvd:
13397dd7cddfSDavid du Colombier 			newstate(ppp, p, Sreqsent);
13407dd7cddfSDavid du Colombier 			break;
13417dd7cddfSDavid du Colombier 		case Sopened:
13427dd7cddfSDavid du Colombier 			config(ppp, p, 0);
13437dd7cddfSDavid du Colombier 			newstate(ppp, p, Sreqsent);
13447dd7cddfSDavid du Colombier 			break;
13457dd7cddfSDavid du Colombier 		}
13467dd7cddfSDavid du Colombier 		break;
13477dd7cddfSDavid du Colombier 	case Lcoderej:
13487dd7cddfSDavid du Colombier 		//newstate(ppp, p, Sclosed);
13497dd7cddfSDavid du Colombier 		syslog(0, LOG, "code reject %d\n", m->data[0]);
13507dd7cddfSDavid du Colombier 		break;
13517dd7cddfSDavid du Colombier 	case Lprotorej:
13527dd7cddfSDavid du Colombier 		proto = nhgets(m->data);
135359cc4ca5SDavid du Colombier 		netlog("ppp: proto reject %ux\n", proto);
13547dd7cddfSDavid du Colombier 		if(proto == Pccp)
13557dd7cddfSDavid du Colombier 			newstate(ppp, ppp->ccp, Sclosed);
13567dd7cddfSDavid du Colombier 		break;
13577dd7cddfSDavid du Colombier 	case Lechoreq:
13589a747e4fSDavid du Colombier 		if(BLEN(b) < 8){
13599a747e4fSDavid du Colombier 			netlog("ppp: short lcp echo request\n");
13609a747e4fSDavid du Colombier 			freeb(b);
13619a747e4fSDavid du Colombier 			return;
13629a747e4fSDavid du Colombier 		}
13637dd7cddfSDavid du Colombier 		m->code = Lechoack;
13649a747e4fSDavid du Colombier 		hnputl(m->data, ppp->magic);
13657dd7cddfSDavid du Colombier 		putframe(ppp, p->proto, b);
13667dd7cddfSDavid du Colombier 		break;
13677dd7cddfSDavid du Colombier 	case Lechoack:
13687dd7cddfSDavid du Colombier 		p->echoack = 1;
13697dd7cddfSDavid du Colombier 		break;
13707dd7cddfSDavid du Colombier 	case Ldiscard:
13717dd7cddfSDavid du Colombier 		/* nothing to do */
13727dd7cddfSDavid du Colombier 		break;
13737dd7cddfSDavid du Colombier 	case Lresetreq:
13747dd7cddfSDavid du Colombier 		if(p->proto != Pccp)
13757dd7cddfSDavid du Colombier 			break;
13767dd7cddfSDavid du Colombier 		ppp->stat.compreset++;
13777dd7cddfSDavid du Colombier 		if(ppp->ctype != nil)
13787dd7cddfSDavid du Colombier 			b = (*ppp->ctype->resetreq)(ppp->cstate, b);
13797dd7cddfSDavid du Colombier 		if(b != nil) {
13807dd7cddfSDavid du Colombier 			m = (Lcpmsg*)b->rptr;
13817dd7cddfSDavid du Colombier 			m->code = Lresetack;
13827dd7cddfSDavid du Colombier 			putframe(ppp, p->proto, b);
13837dd7cddfSDavid du Colombier 		}
13847dd7cddfSDavid du Colombier 		break;
13857dd7cddfSDavid du Colombier 	case Lresetack:
13867dd7cddfSDavid du Colombier 		if(p->proto != Pccp)
13877dd7cddfSDavid du Colombier 			break;
13887dd7cddfSDavid du Colombier 		if(ppp->unctype != nil)
13897dd7cddfSDavid du Colombier 			(*ppp->unctype->resetack)(ppp->uncstate, b);
13907dd7cddfSDavid du Colombier 		break;
13917dd7cddfSDavid du Colombier 	}
13927dd7cddfSDavid du Colombier 
13937dd7cddfSDavid du Colombier 	qunlock(ppp);
13947dd7cddfSDavid du Colombier 	freeb(b);
13957dd7cddfSDavid du Colombier }
13967dd7cddfSDavid du Colombier 
13977dd7cddfSDavid du Colombier /*
13987dd7cddfSDavid du Colombier  *  timer for protocol state machine
13997dd7cddfSDavid du Colombier  */
14007dd7cddfSDavid du Colombier static void
ptimer(PPP * ppp,Pstate * p)14017dd7cddfSDavid du Colombier ptimer(PPP *ppp, Pstate *p)
14027dd7cddfSDavid du Colombier {
14037dd7cddfSDavid du Colombier 	if(p->state == Sopened || p->state == Sclosed)
14047dd7cddfSDavid du Colombier 		return;
14057dd7cddfSDavid du Colombier 
14067dd7cddfSDavid du Colombier 	p->timeout--;
14077dd7cddfSDavid du Colombier 	switch(p->state){
14087dd7cddfSDavid du Colombier 	case Sclosing:
14097dd7cddfSDavid du Colombier 		sendtermreq(ppp, p);
14107dd7cddfSDavid du Colombier 		break;
14117dd7cddfSDavid du Colombier 	case Sreqsent:
14127dd7cddfSDavid du Colombier 	case Sacksent:
14137dd7cddfSDavid du Colombier 		if(p->timeout <= 0)
14147dd7cddfSDavid du Colombier 			newstate(ppp, p, Sclosed);
14157dd7cddfSDavid du Colombier 		else {
14167dd7cddfSDavid du Colombier 			config(ppp, p, 0);
14177dd7cddfSDavid du Colombier 		}
14187dd7cddfSDavid du Colombier 		break;
14197dd7cddfSDavid du Colombier 	case Sackrcvd:
14207dd7cddfSDavid du Colombier 		if(p->timeout <= 0)
14217dd7cddfSDavid du Colombier 			newstate(ppp, p, Sclosed);
14227dd7cddfSDavid du Colombier 		else {
14237dd7cddfSDavid du Colombier 			config(ppp, p, 0);
14247dd7cddfSDavid du Colombier 			newstate(ppp, p, Sreqsent);
14257dd7cddfSDavid du Colombier 		}
14267dd7cddfSDavid du Colombier 		break;
14277dd7cddfSDavid du Colombier 	}
14287dd7cddfSDavid du Colombier }
14297dd7cddfSDavid du Colombier 
1430bedadc12SDavid du Colombier /* paptimer -- pap timer event handler
1431bedadc12SDavid du Colombier  *
1432bedadc12SDavid du Colombier  * If PAP authorization hasn't come through, resend an authreqst.  If
1433bedadc12SDavid du Colombier  * the maximum number of requests have been sent (~ 30 seconds), give
1434bedadc12SDavid du Colombier  * up.
1435bedadc12SDavid du Colombier  *
1436bedadc12SDavid du Colombier  */
143780ee5cbfSDavid du Colombier static void
authtimer(PPP * ppp)143880ee5cbfSDavid du Colombier authtimer(PPP* ppp)
143980ee5cbfSDavid du Colombier {
144080ee5cbfSDavid du Colombier 	if(ppp->chap->proto != APpasswd)
144180ee5cbfSDavid du Colombier 		return;
144280ee5cbfSDavid du Colombier 
144380ee5cbfSDavid du Colombier 	if(ppp->chap->id < 21)
144480ee5cbfSDavid du Colombier 		putpaprequest(ppp);
144580ee5cbfSDavid du Colombier 	else {
144680ee5cbfSDavid du Colombier 		terminate(ppp, 0);
144780ee5cbfSDavid du Colombier 		netlog("ppp: pap timed out--not authorized\n");
144880ee5cbfSDavid du Colombier 	}
144980ee5cbfSDavid du Colombier }
145080ee5cbfSDavid du Colombier 
145180ee5cbfSDavid du Colombier 
14527dd7cddfSDavid du Colombier /*
14537dd7cddfSDavid du Colombier  *  timer for ppp
14547dd7cddfSDavid du Colombier  */
14557dd7cddfSDavid du Colombier static void
ppptimer(PPP * ppp)14567dd7cddfSDavid du Colombier ppptimer(PPP *ppp)
14577dd7cddfSDavid du Colombier {
14587dd7cddfSDavid du Colombier 	while(!dying){
14597dd7cddfSDavid du Colombier 		sleep(Period);
14607dd7cddfSDavid du Colombier 		qlock(ppp);
14617dd7cddfSDavid du Colombier 
14623ff48bf5SDavid du Colombier 		netlog("ppp: ppptimer\n");
14637dd7cddfSDavid du Colombier 		ptimer(ppp, ppp->lcp);
14647dd7cddfSDavid du Colombier 		if(ppp->lcp->state == Sopened) {
146580ee5cbfSDavid du Colombier 			switch(ppp->phase){
146680ee5cbfSDavid du Colombier 			case Pnet:
14677dd7cddfSDavid du Colombier 				ptimer(ppp, ppp->ccp);
14687dd7cddfSDavid du Colombier 				ptimer(ppp, ppp->ipcp);
146980ee5cbfSDavid du Colombier 				break;
147080ee5cbfSDavid du Colombier 			case Pauth:
147180ee5cbfSDavid du Colombier 				authtimer(ppp);
147280ee5cbfSDavid du Colombier 				break;
147380ee5cbfSDavid du Colombier 			}
14747dd7cddfSDavid du Colombier 		}
14757dd7cddfSDavid du Colombier 
14767dd7cddfSDavid du Colombier 		/* link quality measurement */
14777dd7cddfSDavid du Colombier 		if(ppp->period && --(ppp->timeout) <= 0){
14787dd7cddfSDavid du Colombier 			ppp->timeout = ppp->period;
14797dd7cddfSDavid du Colombier 			putlqm(ppp);
14807dd7cddfSDavid du Colombier 		}
14817dd7cddfSDavid du Colombier 
14827dd7cddfSDavid du Colombier 		qunlock(ppp);
14837dd7cddfSDavid du Colombier 	}
14847dd7cddfSDavid du Colombier }
14857dd7cddfSDavid du Colombier 
14867dd7cddfSDavid du Colombier static void
setdefroute(char * net,Ipaddr gate)14877dd7cddfSDavid du Colombier setdefroute(char *net, Ipaddr gate)
14887dd7cddfSDavid du Colombier {
14897dd7cddfSDavid du Colombier 	int fd;
14907dd7cddfSDavid du Colombier 	char path[128];
14917dd7cddfSDavid du Colombier 
14927dd7cddfSDavid du Colombier 	snprint(path, sizeof path, "%s/iproute", net);
14937dd7cddfSDavid du Colombier 	fd = open(path, ORDWR);
14947dd7cddfSDavid du Colombier 	if(fd < 0)
14957dd7cddfSDavid du Colombier 		return;
14967dd7cddfSDavid du Colombier 	fprint(fd, "add 0 0 %I", gate);
14977dd7cddfSDavid du Colombier 	close(fd);
14987dd7cddfSDavid du Colombier }
14997dd7cddfSDavid du Colombier 
15006b6b9ac8SDavid du Colombier enum
15016b6b9ac8SDavid du Colombier {
15026b6b9ac8SDavid du Colombier 	Mofd=	32,
15036b6b9ac8SDavid du Colombier };
15046b6b9ac8SDavid du Colombier struct
15056b6b9ac8SDavid du Colombier {
15066b6b9ac8SDavid du Colombier 	Lock;
15076b6b9ac8SDavid du Colombier 
15086b6b9ac8SDavid du Colombier 	int	fd[Mofd];
15096b6b9ac8SDavid du Colombier 	int	cfd[Mofd];
15106b6b9ac8SDavid du Colombier 	int	n;
15116b6b9ac8SDavid du Colombier } old;
15126b6b9ac8SDavid du Colombier 
15137dd7cddfSDavid du Colombier static char*
ipopen(PPP * ppp)15147dd7cddfSDavid du Colombier ipopen(PPP *ppp)
15157dd7cddfSDavid du Colombier {
15166b6b9ac8SDavid du Colombier 	static int ipinprocpid;
15176b6b9ac8SDavid du Colombier 	int n, cfd, fd;
15187dd7cddfSDavid du Colombier 	char path[128];
15196b6b9ac8SDavid du Colombier 	char buf[128];
15207dd7cddfSDavid du Colombier 
15216b6b9ac8SDavid du Colombier 	if(ipinprocpid <= 0){
15227dd7cddfSDavid du Colombier 		snprint(path, sizeof path, "%s/ipifc/clone", ppp->net);
15237dd7cddfSDavid du Colombier 		cfd = open(path, ORDWR);
15247dd7cddfSDavid du Colombier 		if(cfd < 0)
15257dd7cddfSDavid du Colombier 			return "can't open ip interface";
15267dd7cddfSDavid du Colombier 
15277dd7cddfSDavid du Colombier 		n = read(cfd, buf, sizeof(buf) - 1);
15287dd7cddfSDavid du Colombier 		if(n <= 0){
15297dd7cddfSDavid du Colombier 			close(cfd);
15307dd7cddfSDavid du Colombier 			return "can't open ip interface";
15317dd7cddfSDavid du Colombier 		}
15327dd7cddfSDavid du Colombier 		buf[n] = 0;
15337dd7cddfSDavid du Colombier 
1534a7b22450SDavid du Colombier 		netlog("ppp: setting up IP interface local %I remote %I (valid %d)\n",
1535a7b22450SDavid du Colombier 			ppp->local, ppp->remote, validv4(ppp->remote));
1536a7b22450SDavid du Colombier 		if(!validv4(ppp->remote))
1537a7b22450SDavid du Colombier 			ipmove(ppp->remote, ppp->local);
1538a7b22450SDavid du Colombier 
15397dd7cddfSDavid du Colombier 		snprint(path, sizeof path, "%s/ipifc/%s/data", ppp->net, buf);
15407dd7cddfSDavid du Colombier 		fd = open(path, ORDWR);
15417dd7cddfSDavid du Colombier 		if(fd < 0){
15427dd7cddfSDavid du Colombier 			close(cfd);
15437dd7cddfSDavid du Colombier 			return "can't open ip interface";
15447dd7cddfSDavid du Colombier 		}
15457dd7cddfSDavid du Colombier 
15467dd7cddfSDavid du Colombier 		if(fprint(cfd, "bind pkt") < 0)
15477dd7cddfSDavid du Colombier 			return "binding pkt to ip interface";
15486b6b9ac8SDavid du Colombier 		if(fprint(cfd, "add %I 255.255.255.255 %I %lud proxy", ppp->local,
15496b6b9ac8SDavid du Colombier 			ppp->remote, ppp->mtu-10) < 0){
15507dd7cddfSDavid du Colombier 			close(cfd);
15517dd7cddfSDavid du Colombier 			return "can't set addresses";
15527dd7cddfSDavid du Colombier 		}
155359cc4ca5SDavid du Colombier 		if(primary)
15547dd7cddfSDavid du Colombier 			setdefroute(ppp->net, ppp->remote);
15557dd7cddfSDavid du Colombier 		ppp->ipfd = fd;
15567dd7cddfSDavid du Colombier 		ppp->ipcfd = cfd;
15577dd7cddfSDavid du Colombier 
15587dd7cddfSDavid du Colombier 		/* signal main() that ip is configured */
155974f16c81SDavid du Colombier 		rendezvous((void*)Rmagic, 0);
15607dd7cddfSDavid du Colombier 
15616b6b9ac8SDavid du Colombier 		switch(ipinprocpid = rfork(RFPROC|RFMEM|RFNOWAIT)){
15627dd7cddfSDavid du Colombier 		case -1:
15637dd7cddfSDavid du Colombier 			sysfatal("forking ipinproc");
15647dd7cddfSDavid du Colombier 		case 0:
15657dd7cddfSDavid du Colombier 			ipinproc(ppp);
156659cc4ca5SDavid du Colombier 			terminate(ppp, 1);
15677dd7cddfSDavid du Colombier 			_exits(0);
15687dd7cddfSDavid du Colombier 		}
15696b6b9ac8SDavid du Colombier 	} else {
15706b6b9ac8SDavid du Colombier 		/* we may have changed addresses */
15716b6b9ac8SDavid du Colombier 		if(ipcmp(ppp->local, ppp->curlocal) != 0 ||
15726b6b9ac8SDavid du Colombier 		   ipcmp(ppp->remote, ppp->curremote) != 0){
157339734e7eSDavid du Colombier 			snprint(buf, sizeof buf, "remove %I 255.255.255.255 %I",
157439734e7eSDavid du Colombier 			    ppp->curlocal, ppp->curremote);
15756b6b9ac8SDavid du Colombier 			if(fprint(ppp->ipcfd, "%s", buf) < 0)
15766b6b9ac8SDavid du Colombier 				syslog(0, "ppp", "can't %s: %r", buf);
15776b6b9ac8SDavid du Colombier 			snprint(buf, sizeof buf, "add %I 255.255.255.255 %I %lud proxy",
15786b6b9ac8SDavid du Colombier 			    ppp->local, ppp->remote, ppp->mtu-10);
15796b6b9ac8SDavid du Colombier 			if(fprint(ppp->ipcfd, "%s", buf) < 0)
15806b6b9ac8SDavid du Colombier 				syslog(0, "ppp", "can't %s: %r", buf);
15817dd7cddfSDavid du Colombier 		}
15826b6b9ac8SDavid du Colombier 		syslog(0, "ppp", "%I/%I -> %I/%I", ppp->curlocal, ppp->curremote,
15836b6b9ac8SDavid du Colombier 		   ppp->local, ppp->remote);
15846b6b9ac8SDavid du Colombier 	}
15856b6b9ac8SDavid du Colombier 	ipmove(ppp->curlocal, ppp->local);
15866b6b9ac8SDavid du Colombier 	ipmove(ppp->curremote, ppp->remote);
15877dd7cddfSDavid du Colombier 
15887dd7cddfSDavid du Colombier 	return nil;
15897dd7cddfSDavid du Colombier }
15907dd7cddfSDavid du Colombier 
15917dd7cddfSDavid du Colombier /* return next input IP packet */
15927dd7cddfSDavid du Colombier Block*
pppread(PPP * ppp)15937dd7cddfSDavid du Colombier pppread(PPP *ppp)
15947dd7cddfSDavid du Colombier {
15957dd7cddfSDavid du Colombier 	Block *b, *reply;
15967dd7cddfSDavid du Colombier 	int proto, len;
15977dd7cddfSDavid du Colombier 	Lcpmsg *m;
15987dd7cddfSDavid du Colombier 
15997dd7cddfSDavid du Colombier 	while(!dying){
16007dd7cddfSDavid du Colombier 		b = getframe(ppp, &proto);
16017dd7cddfSDavid du Colombier 		if(b == nil)
16027dd7cddfSDavid du Colombier 			return nil;
16037dd7cddfSDavid du Colombier 
16047dd7cddfSDavid du Colombier Again:
16057dd7cddfSDavid du Colombier 		switch(proto){
16067dd7cddfSDavid du Colombier 		case Plcp:
16077dd7cddfSDavid du Colombier 			rcv(ppp, ppp->lcp, b);
16087dd7cddfSDavid du Colombier 			break;
16097dd7cddfSDavid du Colombier 		case Pccp:
16107dd7cddfSDavid du Colombier 			rcv(ppp, ppp->ccp, b);
16117dd7cddfSDavid du Colombier 			break;
16127dd7cddfSDavid du Colombier 		case Pipcp:
16137dd7cddfSDavid du Colombier 			rcv(ppp, ppp->ipcp, b);
16147dd7cddfSDavid du Colombier 			break;
16157dd7cddfSDavid du Colombier 		case Pip:
16167dd7cddfSDavid du Colombier 			if(ppp->ipcp->state == Sopened)
16177dd7cddfSDavid du Colombier 				return b;
16187dd7cddfSDavid du Colombier 			netlog("ppp: IP recved: link not up\n");
16197dd7cddfSDavid du Colombier 			freeb(b);
16207dd7cddfSDavid du Colombier 			break;
16217dd7cddfSDavid du Colombier 		case Plqm:
16227dd7cddfSDavid du Colombier 			getlqm(ppp, b);
16237dd7cddfSDavid du Colombier 			break;
16247dd7cddfSDavid du Colombier 		case Pchap:
16257dd7cddfSDavid du Colombier 			getchap(ppp, b);
16267dd7cddfSDavid du Colombier 			break;
162780ee5cbfSDavid du Colombier 		case Ppasswd:
162880ee5cbfSDavid du Colombier 			getpap(ppp, b);
162980ee5cbfSDavid du Colombier 			break;
16307dd7cddfSDavid du Colombier 		case Pvjctcp:
16317dd7cddfSDavid du Colombier 		case Pvjutcp:
16327dd7cddfSDavid du Colombier 			if(ppp->ipcp->state != Sopened){
16337dd7cddfSDavid du Colombier 				netlog("ppp: VJ tcp recved: link not up\n");
16347dd7cddfSDavid du Colombier 				freeb(b);
16357dd7cddfSDavid du Colombier 				break;
16367dd7cddfSDavid du Colombier 			}
16377dd7cddfSDavid du Colombier 			ppp->stat.vjin++;
16387dd7cddfSDavid du Colombier 			b = tcpuncompress(ppp->ctcp, b, proto);
16397dd7cddfSDavid du Colombier 			if(b != nil)
16407dd7cddfSDavid du Colombier 				return b;
16417dd7cddfSDavid du Colombier 			ppp->stat.vjfail++;
16427dd7cddfSDavid du Colombier 			break;
16437dd7cddfSDavid du Colombier 		case Pcdata:
16447dd7cddfSDavid du Colombier 			ppp->stat.uncomp++;
16457dd7cddfSDavid du Colombier 			if(ppp->ccp->state != Sopened){
16467dd7cddfSDavid du Colombier 				netlog("ppp: compressed data recved: link not up\n");
16477dd7cddfSDavid du Colombier 				freeb(b);
16487dd7cddfSDavid du Colombier 				break;
16497dd7cddfSDavid du Colombier 			}
16507dd7cddfSDavid du Colombier 			if(ppp->unctype == nil) {
16517dd7cddfSDavid du Colombier 				netlog("ppp: compressed data recved: no compression\n");
16527dd7cddfSDavid du Colombier 				freeb(b);
16537dd7cddfSDavid du Colombier 				break;
16547dd7cddfSDavid du Colombier 			}
16557dd7cddfSDavid du Colombier 			len = BLEN(b);
16567dd7cddfSDavid du Colombier 			b = (*ppp->unctype->uncompress)(ppp, b, &proto, &reply);
16577dd7cddfSDavid du Colombier 			if(reply != nil){
16587dd7cddfSDavid du Colombier 				/* send resetreq */
16597dd7cddfSDavid du Colombier 				ppp->stat.uncompreset++;
16607dd7cddfSDavid du Colombier 				putframe(ppp, Pccp, reply);
16617dd7cddfSDavid du Colombier 				freeb(reply);
16627dd7cddfSDavid du Colombier 			}
16637dd7cddfSDavid du Colombier 			if(b == nil)
16647dd7cddfSDavid du Colombier 				break;
16657dd7cddfSDavid du Colombier 			ppp->stat.uncompin += len;
16667dd7cddfSDavid du Colombier 			ppp->stat.uncompout += BLEN(b);
16677dd7cddfSDavid du Colombier /* netlog("ppp: uncompressed frame %ux %d %d (%d uchars)\n", proto, b->rptr[0], b->rptr[1], BLEN(b)); /* */
16687dd7cddfSDavid du Colombier 			goto Again;
16697dd7cddfSDavid du Colombier 		default:
16707dd7cddfSDavid du Colombier 			syslog(0, LOG, "unknown proto %ux", proto);
16717dd7cddfSDavid du Colombier 			if(ppp->lcp->state == Sopened){
16727dd7cddfSDavid du Colombier 				/* reject the protocol */
16737dd7cddfSDavid du Colombier 				b->rptr -= 6;
16747dd7cddfSDavid du Colombier 				m = (Lcpmsg*)b->rptr;
16757dd7cddfSDavid du Colombier 				m->code = Lprotorej;
16767dd7cddfSDavid du Colombier 				m->id = ++ppp->lcp->id;
16777dd7cddfSDavid du Colombier 				hnputs(m->data, proto);
16787dd7cddfSDavid du Colombier 				hnputs(m->len, BLEN(b));
16797dd7cddfSDavid du Colombier 				putframe(ppp, Plcp, b);
16807dd7cddfSDavid du Colombier 			}
16817dd7cddfSDavid du Colombier 			freeb(b);
16827dd7cddfSDavid du Colombier 			break;
16837dd7cddfSDavid du Colombier 		}
16847dd7cddfSDavid du Colombier 	}
16857dd7cddfSDavid du Colombier 	return nil;
16867dd7cddfSDavid du Colombier }
16877dd7cddfSDavid du Colombier 
16887dd7cddfSDavid du Colombier /* transmit an IP packet */
16897dd7cddfSDavid du Colombier int
pppwrite(PPP * ppp,Block * b)16907dd7cddfSDavid du Colombier pppwrite(PPP *ppp, Block *b)
16917dd7cddfSDavid du Colombier {
16927dd7cddfSDavid du Colombier 	int proto;
16937dd7cddfSDavid du Colombier 	int len;
16947dd7cddfSDavid du Colombier 
16957dd7cddfSDavid du Colombier 	qlock(ppp);
16967dd7cddfSDavid du Colombier 	/* can't send ip packets till we're established */
16977dd7cddfSDavid du Colombier 	if(ppp->ipcp->state != Sopened) {
16987dd7cddfSDavid du Colombier 		qunlock(ppp);
16997dd7cddfSDavid du Colombier 		syslog(0, LOG, "IP write: link not up");
17007dd7cddfSDavid du Colombier 		len = blen(b);
17017dd7cddfSDavid du Colombier 		freeb(b);
17027dd7cddfSDavid du Colombier 		return len;
17037dd7cddfSDavid du Colombier 	}
17047dd7cddfSDavid du Colombier 
17057dd7cddfSDavid du Colombier 	proto = Pip;
17067dd7cddfSDavid du Colombier 	ppp->stat.ipsend++;
17077dd7cddfSDavid du Colombier 
17087dd7cddfSDavid du Colombier 	if(ppp->ipcp->flags & Fipcompress){
17097dd7cddfSDavid du Colombier 		b = compress(ppp->ctcp, b, &proto);
17107dd7cddfSDavid du Colombier 		if(b == nil){
17117dd7cddfSDavid du Colombier 			qunlock(ppp);
17127dd7cddfSDavid du Colombier 			return 0;
17137dd7cddfSDavid du Colombier 		}
17147dd7cddfSDavid du Colombier 		if(proto != Pip)
17157dd7cddfSDavid du Colombier 			ppp->stat.vjout++;
17167dd7cddfSDavid du Colombier 	}
17177dd7cddfSDavid du Colombier 
171859cc4ca5SDavid du Colombier 	if(ppp->ctype != nil) {
17197dd7cddfSDavid du Colombier 		len = blen(b);
17207dd7cddfSDavid du Colombier 		b = (*ppp->ctype->compress)(ppp, proto, b, &proto);
17217dd7cddfSDavid du Colombier 		if(proto == Pcdata) {
17227dd7cddfSDavid du Colombier 			ppp->stat.comp++;
17237dd7cddfSDavid du Colombier 			ppp->stat.compin += len;
17247dd7cddfSDavid du Colombier 			ppp->stat.compout += blen(b);
17257dd7cddfSDavid du Colombier 		}
17267dd7cddfSDavid du Colombier 	}
17277dd7cddfSDavid du Colombier 
17287dd7cddfSDavid du Colombier 	if(putframe(ppp, proto, b) < 0) {
17297dd7cddfSDavid du Colombier 		qunlock(ppp);
17307dd7cddfSDavid du Colombier 		freeb(b);
17317dd7cddfSDavid du Colombier 		return -1;
17327dd7cddfSDavid du Colombier 	}
17337dd7cddfSDavid du Colombier 	qunlock(ppp);
17347dd7cddfSDavid du Colombier 
17357dd7cddfSDavid du Colombier 	len = blen(b);
17367dd7cddfSDavid du Colombier 	freeb(b);
17377dd7cddfSDavid du Colombier 	return len;
17387dd7cddfSDavid du Colombier }
17397dd7cddfSDavid du Colombier 
17407dd7cddfSDavid du Colombier static void
terminate(PPP * ppp,int kill)17417dd7cddfSDavid du Colombier terminate(PPP *ppp, int kill)
17427dd7cddfSDavid du Colombier {
17437dd7cddfSDavid du Colombier 	close(ppp->ipfd);
17447dd7cddfSDavid du Colombier 	ppp->ipfd = -1;
17457dd7cddfSDavid du Colombier 	close(ppp->ipcfd);
17467dd7cddfSDavid du Colombier 	ppp->ipcfd = -1;
1747d9306527SDavid du Colombier 	close(ppp->mediain);
1748d9306527SDavid du Colombier 	close(ppp->mediaout);
1749d9306527SDavid du Colombier 	ppp->mediain = -1;
1750d9306527SDavid du Colombier 	ppp->mediaout = -1;
17517dd7cddfSDavid du Colombier 	dying = 1;
17527dd7cddfSDavid du Colombier 
17537dd7cddfSDavid du Colombier 	if(kill)
17547dd7cddfSDavid du Colombier 		postnote(PNGROUP, getpid(), "die");
17557dd7cddfSDavid du Colombier }
17567dd7cddfSDavid du Colombier 
17577dd7cddfSDavid du Colombier typedef struct Iphdr Iphdr;
17587dd7cddfSDavid du Colombier struct Iphdr
17597dd7cddfSDavid du Colombier {
17607dd7cddfSDavid du Colombier 	uchar	vihl;		/* Version and header length */
17617dd7cddfSDavid du Colombier 	uchar	tos;		/* Type of service */
17627dd7cddfSDavid du Colombier 	uchar	length[2];	/* packet length */
17637dd7cddfSDavid du Colombier 	uchar	id[2];		/* Identification */
17647dd7cddfSDavid du Colombier 	uchar	frag[2];	/* Fragment information */
17657dd7cddfSDavid du Colombier 	uchar	ttl;		/* Time to live */
17667dd7cddfSDavid du Colombier 	uchar	proto;		/* Protocol */
17677dd7cddfSDavid du Colombier 	uchar	cksum[2];	/* Header checksum */
17687dd7cddfSDavid du Colombier 	uchar	src[4];		/* Ip source (uchar ordering unimportant) */
17697dd7cddfSDavid du Colombier 	uchar	dst[4];		/* Ip destination (uchar ordering unimportant) */
17707dd7cddfSDavid du Colombier };
17717dd7cddfSDavid du Colombier 
17727dd7cddfSDavid du Colombier static void
ipinproc(PPP * ppp)17737dd7cddfSDavid du Colombier ipinproc(PPP *ppp)
17747dd7cddfSDavid du Colombier {
17757dd7cddfSDavid du Colombier 	Block *b;
17767dd7cddfSDavid du Colombier 	int m, n;
17777dd7cddfSDavid du Colombier 	Iphdr *ip;
17787dd7cddfSDavid du Colombier 
17797dd7cddfSDavid du Colombier 	while(!dying){
17806b6b9ac8SDavid du Colombier 
17817dd7cddfSDavid du Colombier 		b = allocb(Buflen);
17827dd7cddfSDavid du Colombier 		n = read(ppp->ipfd, b->wptr, b->lim-b->wptr);
17837dd7cddfSDavid du Colombier 		if(n < 0)
17847dd7cddfSDavid du Colombier 			break;
17857dd7cddfSDavid du Colombier 
17867dd7cddfSDavid du Colombier 		/* trim packet if there's padding (e.g. from ether) */
17877dd7cddfSDavid du Colombier 		ip = (Iphdr*)b->rptr;
17887dd7cddfSDavid du Colombier 		m = nhgets(ip->length);
17897dd7cddfSDavid du Colombier 		if(m < n && m > 0)
17907dd7cddfSDavid du Colombier 			n = m;
17917dd7cddfSDavid du Colombier 		b->wptr += n;
17927dd7cddfSDavid du Colombier 
17937dd7cddfSDavid du Colombier 		if(pppwrite(ppp, b) < 0)
17947dd7cddfSDavid du Colombier 			break;
17957dd7cddfSDavid du Colombier 	}
17967dd7cddfSDavid du Colombier }
17977dd7cddfSDavid du Colombier 
17987dd7cddfSDavid du Colombier static void
catchdie(void *,char * msg)179959cc4ca5SDavid du Colombier catchdie(void*, char *msg)
180059cc4ca5SDavid du Colombier {
180159cc4ca5SDavid du Colombier 	if(strstr(msg, "die") != nil)
180259cc4ca5SDavid du Colombier 		noted(NCONT);
180359cc4ca5SDavid du Colombier 	else
180459cc4ca5SDavid du Colombier 		noted(NDFLT);
180559cc4ca5SDavid du Colombier }
180659cc4ca5SDavid du Colombier 
180759cc4ca5SDavid du Colombier static void
hexdump(uchar * a,int na)18089a747e4fSDavid du Colombier hexdump(uchar *a, int na)
18099a747e4fSDavid du Colombier {
18109a747e4fSDavid du Colombier 	int i;
18119a747e4fSDavid du Colombier 	char buf[80];
18129a747e4fSDavid du Colombier 
18139a747e4fSDavid du Colombier 	fprint(2, "dump %p %d\n", a, na);
18149a747e4fSDavid du Colombier 	buf[0] = '\0';
18159a747e4fSDavid du Colombier 	for(i=0; i<na; i++){
18169a747e4fSDavid du Colombier 		sprint(buf+strlen(buf), " %.2ux", a[i]);
18179a747e4fSDavid du Colombier 		if(i%16 == 7)
18189a747e4fSDavid du Colombier 			sprint(buf+strlen(buf), " --");
18199a747e4fSDavid du Colombier 		if(i%16==15){
18209a747e4fSDavid du Colombier 			sprint(buf+strlen(buf), "\n");
18219a747e4fSDavid du Colombier 			write(2, buf, strlen(buf));
18229a747e4fSDavid du Colombier 			buf[0] = '\0';
18239a747e4fSDavid du Colombier 		}
18249a747e4fSDavid du Colombier 	}
18259a747e4fSDavid du Colombier 	if(i%16){
18269a747e4fSDavid du Colombier 		sprint(buf+strlen(buf), "\n");
18279a747e4fSDavid du Colombier 		write(2, buf, strlen(buf));
18289a747e4fSDavid du Colombier 	}
18299a747e4fSDavid du Colombier }
18309a747e4fSDavid du Colombier 
18319a747e4fSDavid du Colombier static void
mediainproc(PPP * ppp)18327dd7cddfSDavid du Colombier mediainproc(PPP *ppp)
18337dd7cddfSDavid du Colombier {
18347dd7cddfSDavid du Colombier 	Block *b;
18357dd7cddfSDavid du Colombier 	Ipaddr remote;
18367dd7cddfSDavid du Colombier 
183759cc4ca5SDavid du Colombier 	notify(catchdie);
18387dd7cddfSDavid du Colombier 	while(!dying){
18397dd7cddfSDavid du Colombier 		b = pppread(ppp);
18409a747e4fSDavid du Colombier 		if(b == nil){
18419a747e4fSDavid du Colombier 			syslog(0, LOG, "pppread return nil");
18427dd7cddfSDavid du Colombier 			break;
18439a747e4fSDavid du Colombier 		}
18447dd7cddfSDavid du Colombier 		ppp->stat.iprecv++;
18457dd7cddfSDavid du Colombier 		if(ppp->ipcp->state != Sopened) {
18467dd7cddfSDavid du Colombier 			ppp->stat.iprecvnotup++;
18477dd7cddfSDavid du Colombier 			freeb(b);
18487dd7cddfSDavid du Colombier 			continue;
18497dd7cddfSDavid du Colombier 		}
18507dd7cddfSDavid du Colombier 
18517dd7cddfSDavid du Colombier 		if(server) {
18527dd7cddfSDavid du Colombier 			v4tov6(remote, b->rptr+12);
18537dd7cddfSDavid du Colombier 			if(ipcmp(remote, ppp->remote) != 0) {
18547dd7cddfSDavid du Colombier 				ppp->stat.iprecvbadsrc++;
18557dd7cddfSDavid du Colombier 				freeb(b);
18567dd7cddfSDavid du Colombier 				continue;
18577dd7cddfSDavid du Colombier 			}
18587dd7cddfSDavid du Colombier 		}
18599a747e4fSDavid du Colombier 		if(debug > 1){
18609a747e4fSDavid du Colombier 			netlog("ip write pkt %p %d\n", b->rptr, blen(b));
18619a747e4fSDavid du Colombier 			hexdump(b->rptr, blen(b));
18629a747e4fSDavid du Colombier 		}
18637dd7cddfSDavid du Colombier 		if(write(ppp->ipfd, b->rptr, blen(b)) < 0) {
18649a747e4fSDavid du Colombier 			syslog(0, LOG, "error writing to pktifc");
18657dd7cddfSDavid du Colombier 			freeb(b);
18667dd7cddfSDavid du Colombier 			break;
18677dd7cddfSDavid du Colombier 		}
18687dd7cddfSDavid du Colombier 
18697dd7cddfSDavid du Colombier 		freeb(b);
18707dd7cddfSDavid du Colombier 	}
18717dd7cddfSDavid du Colombier 
18726b6b9ac8SDavid du Colombier 	netlog(": remote=%I: ppp shutting down\n", ppp->remote);
18736b6b9ac8SDavid du Colombier 	syslog(0, LOG, ": remote=%I: ppp shutting down", ppp->remote);
18747dd7cddfSDavid du Colombier 	syslog(0, LOG, "\t\tppp send = %lud/%lud recv= %lud/%lud",
18757dd7cddfSDavid du Colombier 		ppp->out.packets, ppp->out.uchars,
18767dd7cddfSDavid du Colombier 		ppp->in.packets, ppp->in.uchars);
18777dd7cddfSDavid du Colombier 	syslog(0, LOG, "\t\tip send=%lud", ppp->stat.ipsend);
18787dd7cddfSDavid du Colombier 	syslog(0, LOG, "\t\tip recv=%lud notup=%lud badsrc=%lud",
18797dd7cddfSDavid du Colombier 		ppp->stat.iprecv, ppp->stat.iprecvnotup, ppp->stat.iprecvbadsrc);
18807dd7cddfSDavid du Colombier 	syslog(0, LOG, "\t\tcompress=%lud in=%lud out=%lud reset=%lud",
18817dd7cddfSDavid du Colombier 		ppp->stat.comp, ppp->stat.compin, ppp->stat.compout, ppp->stat.compreset);
18827dd7cddfSDavid du Colombier 	syslog(0, LOG, "\t\tuncompress=%lud in=%lud out=%lud reset=%lud",
18837dd7cddfSDavid du Colombier 		ppp->stat.uncomp, ppp->stat.uncompin, ppp->stat.uncompout,
18847dd7cddfSDavid du Colombier 		ppp->stat.uncompreset);
18857dd7cddfSDavid du Colombier 	syslog(0, LOG, "\t\tvjin=%lud vjout=%lud vjfail=%lud",
18867dd7cddfSDavid du Colombier 		ppp->stat.vjin, ppp->stat.vjout, ppp->stat.vjfail);
18877dd7cddfSDavid du Colombier }
18887dd7cddfSDavid du Colombier 
18897dd7cddfSDavid du Colombier /*
18907dd7cddfSDavid du Colombier  *  link quality management
18917dd7cddfSDavid du Colombier  */
18927dd7cddfSDavid du Colombier static void
getlqm(PPP * ppp,Block * b)18937dd7cddfSDavid du Colombier getlqm(PPP *ppp, Block *b)
18947dd7cddfSDavid du Colombier {
18957dd7cddfSDavid du Colombier 	Qualpkt *p;
18967dd7cddfSDavid du Colombier 
18977dd7cddfSDavid du Colombier 	p = (Qualpkt*)b->rptr;
18987dd7cddfSDavid du Colombier 	if(BLEN(b) == sizeof(Qualpkt)){
18997dd7cddfSDavid du Colombier 		ppp->in.reports++;
19007dd7cddfSDavid du Colombier 		ppp->pout.reports = nhgetl(p->peeroutreports);
19017dd7cddfSDavid du Colombier 		ppp->pout.packets = nhgetl(p->peeroutpackets);
19027dd7cddfSDavid du Colombier 		ppp->pout.uchars = nhgetl(p->peeroutuchars);
19037dd7cddfSDavid du Colombier 		ppp->pin.reports = nhgetl(p->peerinreports);
19047dd7cddfSDavid du Colombier 		ppp->pin.packets = nhgetl(p->peerinpackets);
19057dd7cddfSDavid du Colombier 		ppp->pin.discards = nhgetl(p->peerindiscards);
19067dd7cddfSDavid du Colombier 		ppp->pin.errors = nhgetl(p->peerinerrors);
19077dd7cddfSDavid du Colombier 		ppp->pin.uchars = nhgetl(p->peerinuchars);
19087dd7cddfSDavid du Colombier 
19097dd7cddfSDavid du Colombier 		/* save our numbers at time of reception */
19107dd7cddfSDavid du Colombier 		memmove(&ppp->sin, &ppp->in, sizeof(Qualstats));
19117dd7cddfSDavid du Colombier 
19127dd7cddfSDavid du Colombier 	}
19137dd7cddfSDavid du Colombier 	freeb(b);
19147dd7cddfSDavid du Colombier 	if(ppp->period == 0)
19157dd7cddfSDavid du Colombier 		putlqm(ppp);
19167dd7cddfSDavid du Colombier 
19177dd7cddfSDavid du Colombier }
19187dd7cddfSDavid du Colombier 
19197dd7cddfSDavid du Colombier static void
putlqm(PPP * ppp)19207dd7cddfSDavid du Colombier putlqm(PPP *ppp)
19217dd7cddfSDavid du Colombier {
19227dd7cddfSDavid du Colombier 	Qualpkt *p;
19237dd7cddfSDavid du Colombier 	Block *b;
19247dd7cddfSDavid du Colombier 
19257dd7cddfSDavid du Colombier 	b = allocb(sizeof(Qualpkt));
19267dd7cddfSDavid du Colombier 	b->wptr += sizeof(Qualpkt);
19277dd7cddfSDavid du Colombier 	p = (Qualpkt*)b->rptr;
19287dd7cddfSDavid du Colombier 	hnputl(p->magic, 0);
19297dd7cddfSDavid du Colombier 
19307dd7cddfSDavid du Colombier 	/* heresay (what he last told us) */
19317dd7cddfSDavid du Colombier 	hnputl(p->lastoutreports, ppp->pout.reports);
19327dd7cddfSDavid du Colombier 	hnputl(p->lastoutpackets, ppp->pout.packets);
19337dd7cddfSDavid du Colombier 	hnputl(p->lastoutuchars, ppp->pout.uchars);
19347dd7cddfSDavid du Colombier 
19357dd7cddfSDavid du Colombier 	/* our numbers at time of last reception */
19367dd7cddfSDavid du Colombier 	hnputl(p->peerinreports, ppp->sin.reports);
19377dd7cddfSDavid du Colombier 	hnputl(p->peerinpackets, ppp->sin.packets);
19387dd7cddfSDavid du Colombier 	hnputl(p->peerindiscards, ppp->sin.discards);
19397dd7cddfSDavid du Colombier 	hnputl(p->peerinerrors, ppp->sin.errors);
19407dd7cddfSDavid du Colombier 	hnputl(p->peerinuchars, ppp->sin.uchars);
19417dd7cddfSDavid du Colombier 
19427dd7cddfSDavid du Colombier 	/* our numbers now */
19437dd7cddfSDavid du Colombier 	hnputl(p->peeroutreports, ppp->out.reports+1);
19447dd7cddfSDavid du Colombier 	hnputl(p->peeroutpackets, ppp->out.packets+1);
19457dd7cddfSDavid du Colombier 	hnputl(p->peeroutuchars, ppp->out.uchars+53/*hack*/);
19467dd7cddfSDavid du Colombier 
19477dd7cddfSDavid du Colombier 	putframe(ppp, Plqm, b);
19487dd7cddfSDavid du Colombier 	freeb(b);
19497dd7cddfSDavid du Colombier 	ppp->out.reports++;
19507dd7cddfSDavid du Colombier }
19517dd7cddfSDavid du Colombier 
19527dd7cddfSDavid du Colombier /*
19537dd7cddfSDavid du Colombier  * init challenge response dialog
19547dd7cddfSDavid du Colombier  */
19557dd7cddfSDavid du Colombier static void
chapinit(PPP * ppp)19567dd7cddfSDavid du Colombier chapinit(PPP *ppp)
19577dd7cddfSDavid du Colombier {
19587dd7cddfSDavid du Colombier 	Block *b;
19597dd7cddfSDavid du Colombier 	Lcpmsg *m;
19607dd7cddfSDavid du Colombier 	Chap *c;
19617dd7cddfSDavid du Colombier 	int len;
19629a747e4fSDavid du Colombier 	char *aproto;
19637dd7cddfSDavid du Colombier 
1964dc5a79c1SDavid du Colombier 	getauth(ppp);
1965dc5a79c1SDavid du Colombier 
19667dd7cddfSDavid du Colombier 	c = ppp->chap;
19677dd7cddfSDavid du Colombier 	c->id++;
19687dd7cddfSDavid du Colombier 
19699a747e4fSDavid du Colombier 	switch(c->proto){
19709a747e4fSDavid du Colombier 	default:
19719a747e4fSDavid du Colombier 		abort();
19729a747e4fSDavid du Colombier 	case APmd5:
19739a747e4fSDavid du Colombier 		aproto = "chap";
19749a747e4fSDavid du Colombier 		break;
19759a747e4fSDavid du Colombier 	case APmschap:
19769a747e4fSDavid du Colombier 		aproto = "mschap";
19779a747e4fSDavid du Colombier 		break;
19789a747e4fSDavid du Colombier 	}
19799a747e4fSDavid du Colombier 	if((c->cs = auth_challenge("proto=%q role=server", aproto)) == nil)
19809a747e4fSDavid du Colombier 		sysfatal("auth_challenge: %r");
19819a747e4fSDavid du Colombier 	syslog(0, LOG, ": remote=%I: sending %d byte challenge", ppp->remote, c->cs->nchal);
19829a747e4fSDavid du Colombier 	len = 4 + 1 + c->cs->nchal + strlen(ppp->chapname);
19837dd7cddfSDavid du Colombier 	b = alloclcp(Cchallenge, c->id, len, &m);
19847dd7cddfSDavid du Colombier 
19859a747e4fSDavid du Colombier 	*b->wptr++ = c->cs->nchal;
19869a747e4fSDavid du Colombier 	memmove(b->wptr, c->cs->chal, c->cs->nchal);
19879a747e4fSDavid du Colombier 	b->wptr += c->cs->nchal;
19887dd7cddfSDavid du Colombier 	memmove(b->wptr, ppp->chapname, strlen(ppp->chapname));
19897dd7cddfSDavid du Colombier 	b->wptr += strlen(ppp->chapname);
19907dd7cddfSDavid du Colombier 	hnputs(m->len, len);
19917dd7cddfSDavid du Colombier 	putframe(ppp, Pchap, b);
19927dd7cddfSDavid du Colombier 	freeb(b);
19937dd7cddfSDavid du Colombier 
19947dd7cddfSDavid du Colombier 	c->state = Cchalsent;
19957dd7cddfSDavid du Colombier }
19967dd7cddfSDavid du Colombier 
19979a747e4fSDavid du Colombier /*
19989a747e4fSDavid du Colombier  * BUG factotum should do this
19999a747e4fSDavid du Colombier  */
20009a747e4fSDavid du Colombier enum {
20019a747e4fSDavid du Colombier 	MShashlen = 16,
20029a747e4fSDavid du Colombier 	MSresplen = 24,
20039a747e4fSDavid du Colombier 	MSchallen = 8,
20049a747e4fSDavid du Colombier };
20059a747e4fSDavid du Colombier 
20069a747e4fSDavid du Colombier void
desencrypt(uchar data[8],uchar key[7])20079a747e4fSDavid du Colombier desencrypt(uchar data[8], uchar key[7])
20089a747e4fSDavid du Colombier {
20099a747e4fSDavid du Colombier 	ulong ekey[32];
20109a747e4fSDavid du Colombier 
20119a747e4fSDavid du Colombier 	key_setup(key, ekey);
20129a747e4fSDavid du Colombier 	block_cipher(ekey, data, 0);
20139a747e4fSDavid du Colombier }
20149a747e4fSDavid du Colombier 
20159a747e4fSDavid du Colombier void
nthash(uchar hash[MShashlen],char * passwd)20169a747e4fSDavid du Colombier nthash(uchar hash[MShashlen], char *passwd)
20179a747e4fSDavid du Colombier {
20189a747e4fSDavid du Colombier 	uchar buf[512];
20199a747e4fSDavid du Colombier 	int i;
20209a747e4fSDavid du Colombier 
20219a747e4fSDavid du Colombier 	for(i=0; *passwd && i<sizeof(buf); passwd++) {
20229a747e4fSDavid du Colombier 		buf[i++] = *passwd;
20239a747e4fSDavid du Colombier 		buf[i++] = 0;
20249a747e4fSDavid du Colombier 	}
20259a747e4fSDavid du Colombier 	memset(hash, 0, 16);
20269a747e4fSDavid du Colombier 	md4(buf, i, hash, 0);
20279a747e4fSDavid du Colombier }
20289a747e4fSDavid du Colombier 
20299a747e4fSDavid du Colombier void
mschalresp(uchar resp[MSresplen],uchar hash[MShashlen],uchar chal[MSchallen])20309a747e4fSDavid du Colombier mschalresp(uchar resp[MSresplen], uchar hash[MShashlen], uchar chal[MSchallen])
20319a747e4fSDavid du Colombier {
20329a747e4fSDavid du Colombier 	int i;
20339a747e4fSDavid du Colombier 	uchar buf[21];
20349a747e4fSDavid du Colombier 
20359a747e4fSDavid du Colombier 	memset(buf, 0, sizeof(buf));
20369a747e4fSDavid du Colombier 	memcpy(buf, hash, MShashlen);
20379a747e4fSDavid du Colombier 
20389a747e4fSDavid du Colombier 	for(i=0; i<3; i++) {
20399a747e4fSDavid du Colombier 		memmove(resp+i*MSchallen, chal, MSchallen);
20409a747e4fSDavid du Colombier 		desencrypt(resp+i*MSchallen, buf+i*7);
20419a747e4fSDavid du Colombier 	}
20429a747e4fSDavid du Colombier }
20437dd7cddfSDavid du Colombier 
20447dd7cddfSDavid du Colombier /*
20457dd7cddfSDavid du Colombier  *  challenge response dialog
20467dd7cddfSDavid du Colombier  */
20477dd7cddfSDavid du Colombier extern	int	_asrdresp(int, uchar*, int);
20487dd7cddfSDavid du Colombier 
20497dd7cddfSDavid du Colombier static void
getchap(PPP * ppp,Block * b)20507dd7cddfSDavid du Colombier getchap(PPP *ppp, Block *b)
20517dd7cddfSDavid du Colombier {
20529a747e4fSDavid du Colombier 	AuthInfo *ai;
20537dd7cddfSDavid du Colombier 	Lcpmsg *m;
20549a747e4fSDavid du Colombier 	int len, vlen, i, id, n, nresp;
20557dd7cddfSDavid du Colombier 	char md5buf[512], code;
20567dd7cddfSDavid du Colombier 	Chap *c;
20577dd7cddfSDavid du Colombier 	Chapreply cr;
20587dd7cddfSDavid du Colombier 	MSchapreply mscr;
20599a747e4fSDavid du Colombier 	char uid[PATH];
20609a747e4fSDavid du Colombier 	uchar digest[16], *p, *resp, sdigest[SHA1dlen];
20619a747e4fSDavid du Colombier 	uchar mshash[MShashlen], mshash2[MShashlen];
20629a747e4fSDavid du Colombier 	DigestState *s;
20639a747e4fSDavid du Colombier 	uchar msresp[2*MSresplen+1];
20647dd7cddfSDavid du Colombier 
20657dd7cddfSDavid du Colombier 	m = (Lcpmsg*)b->rptr;
20667dd7cddfSDavid du Colombier 	len = nhgets(m->len);
20677dd7cddfSDavid du Colombier 	if(BLEN(b) < len){
20687dd7cddfSDavid du Colombier 		syslog(0, LOG, "short chap message");
20697dd7cddfSDavid du Colombier 		freeb(b);
20707dd7cddfSDavid du Colombier 		return;
20717dd7cddfSDavid du Colombier 	}
20727dd7cddfSDavid du Colombier 
20737dd7cddfSDavid du Colombier 	qlock(ppp);
20747dd7cddfSDavid du Colombier 
20757dd7cddfSDavid du Colombier 	switch(m->code){
20767dd7cddfSDavid du Colombier 	case Cchallenge:
2077dc5a79c1SDavid du Colombier 		getauth(ppp);
2078dc5a79c1SDavid du Colombier 
20797dd7cddfSDavid du Colombier 		vlen = m->data[0];
20807dd7cddfSDavid du Colombier 		if(vlen > len - 5) {
20817dd7cddfSDavid du Colombier 			netlog("PPP: chap: bad challenge len\n");
20827dd7cddfSDavid du Colombier 			break;
20837dd7cddfSDavid du Colombier 		}
20847dd7cddfSDavid du Colombier 
20859a747e4fSDavid du Colombier 		id = m->id;
20869a747e4fSDavid du Colombier 		switch(ppp->chap->proto){
20879a747e4fSDavid du Colombier 		default:
20889a747e4fSDavid du Colombier 			abort();
20899a747e4fSDavid du Colombier 		case APmd5:
20907dd7cddfSDavid du Colombier 			md5buf[0] = m->id;
20917dd7cddfSDavid du Colombier 			strcpy(md5buf+1, ppp->secret);
20927dd7cddfSDavid du Colombier 			n = strlen(ppp->secret) + 1;
20937dd7cddfSDavid du Colombier 			memmove(md5buf+n, m->data+1, vlen);
20947dd7cddfSDavid du Colombier 			n += vlen;
20959a747e4fSDavid du Colombier 			md5((uchar*)md5buf, n, digest, nil);
20969a747e4fSDavid du Colombier 			resp = digest;
20979a747e4fSDavid du Colombier 			nresp = 16;
20989a747e4fSDavid du Colombier 			break;
20999a747e4fSDavid du Colombier 		case APmschap:
21009a747e4fSDavid du Colombier 			nthash(mshash, ppp->secret);
21019a747e4fSDavid du Colombier 			memset(msresp, 0, sizeof msresp);
21029a747e4fSDavid du Colombier 			mschalresp(msresp+MSresplen, mshash, m->data+1);
21039a747e4fSDavid du Colombier 			resp = msresp;
21049a747e4fSDavid du Colombier 			nresp = sizeof msresp;
21059a747e4fSDavid du Colombier 			nthash(mshash, ppp->secret);
21069a747e4fSDavid du Colombier 			md4(mshash, 16, mshash2, 0);
21079a747e4fSDavid du Colombier 			s = sha1(mshash2, 16, 0, 0);
21089a747e4fSDavid du Colombier 			sha1(mshash2, 16, 0, s);
21099a747e4fSDavid du Colombier 			sha1(m->data+1, 8, sdigest, s);
21109a747e4fSDavid du Colombier 			memmove(ppp->key, sdigest, 16);
21119a747e4fSDavid du Colombier 			break;
21129a747e4fSDavid du Colombier 		}
21139a747e4fSDavid du Colombier 		len = 4 + 1 + nresp + strlen(ppp->chapname);
21147dd7cddfSDavid du Colombier 		freeb(b);
21159a747e4fSDavid du Colombier 		b = alloclcp(Cresponse, id, len, &m);
21169a747e4fSDavid du Colombier 		*b->wptr++ = nresp;
21179a747e4fSDavid du Colombier 		memmove(b->wptr, resp, nresp);
21189a747e4fSDavid du Colombier 		b->wptr += nresp;
21197dd7cddfSDavid du Colombier 		memmove(b->wptr, ppp->chapname, strlen(ppp->chapname));
21207dd7cddfSDavid du Colombier 		b->wptr += strlen(ppp->chapname);
21217dd7cddfSDavid du Colombier 		hnputs(m->len, len);
21229a747e4fSDavid du Colombier 		netlog("PPP: sending response len %d\n", len);
21237dd7cddfSDavid du Colombier 		putframe(ppp, Pchap, b);
21247dd7cddfSDavid du Colombier 		break;
21257dd7cddfSDavid du Colombier 	case Cresponse:
21267dd7cddfSDavid du Colombier 		c = ppp->chap;
21277dd7cddfSDavid du Colombier 		vlen = m->data[0];
21287dd7cddfSDavid du Colombier 		if(m->id != c->id) {
21297dd7cddfSDavid du Colombier 			netlog("PPP: chap: bad response id\n");
21307dd7cddfSDavid du Colombier 			break;
21317dd7cddfSDavid du Colombier 		}
21327dd7cddfSDavid du Colombier 		switch(c->proto) {
21337dd7cddfSDavid du Colombier 		default:
21347dd7cddfSDavid du Colombier 			sysfatal("unknown chap protocol: %d", c->proto);
21357dd7cddfSDavid du Colombier 		case APmd5:
21367dd7cddfSDavid du Colombier 			if(vlen > len - 5 || vlen != 16) {
21377dd7cddfSDavid du Colombier 				netlog("PPP: chap: bad response len\n");
21387dd7cddfSDavid du Colombier 				break;
21397dd7cddfSDavid du Colombier 			}
21407dd7cddfSDavid du Colombier 
21417dd7cddfSDavid du Colombier 			cr.id = m->id;
21427dd7cddfSDavid du Colombier 			memmove(cr.resp, m->data+1, 16);
21437dd7cddfSDavid du Colombier 			memset(uid, 0, sizeof(uid));
21447dd7cddfSDavid du Colombier 			n = len-5-vlen;
21459a747e4fSDavid du Colombier 			if(n >= PATH)
21469a747e4fSDavid du Colombier 				n = PATH-1;
21477dd7cddfSDavid du Colombier 			memmove(uid, m->data+1+vlen, n);
21489a747e4fSDavid du Colombier 			c->cs->user = uid;
21499a747e4fSDavid du Colombier 			c->cs->resp = &cr;
21509a747e4fSDavid du Colombier 			c->cs->nresp = sizeof cr;
21517dd7cddfSDavid du Colombier 			break;
21527dd7cddfSDavid du Colombier 		case APmschap:
21537dd7cddfSDavid du Colombier 			if(vlen > len - 5 || vlen != 49) {
21547dd7cddfSDavid du Colombier 				netlog("PPP: chap: bad response len\n");
21557dd7cddfSDavid du Colombier 				break;
21567dd7cddfSDavid du Colombier 			}
21577dd7cddfSDavid du Colombier 			memset(&mscr, 0, sizeof(mscr));
21587dd7cddfSDavid du Colombier 			memmove(mscr.LMresp, m->data+1, 24);
21597dd7cddfSDavid du Colombier 			memmove(mscr.NTresp, m->data+24+1, 24);
21607dd7cddfSDavid du Colombier 			n = len-5-vlen;
21617dd7cddfSDavid du Colombier 			p = m->data+1+vlen;
21627dd7cddfSDavid du Colombier 			/* remove domain name */
21637dd7cddfSDavid du Colombier 			for(i=0; i<n; i++) {
21647dd7cddfSDavid du Colombier 				if(p[i] == '\\') {
21657dd7cddfSDavid du Colombier 					p += i+1;
21667dd7cddfSDavid du Colombier 					n -= i+1;
21677dd7cddfSDavid du Colombier 					break;
21687dd7cddfSDavid du Colombier 				}
21697dd7cddfSDavid du Colombier 			}
21709a747e4fSDavid du Colombier 			if(n >= PATH)
21719a747e4fSDavid du Colombier 				n = PATH-1;
21727dd7cddfSDavid du Colombier 			memset(uid, 0, sizeof(uid));
21737dd7cddfSDavid du Colombier 			memmove(uid, p, n);
21749a747e4fSDavid du Colombier 			c->cs->user = uid;
21759a747e4fSDavid du Colombier 			c->cs->resp = &mscr;
21769a747e4fSDavid du Colombier 			c->cs->nresp = sizeof mscr;
21777dd7cddfSDavid du Colombier 			break;
21787dd7cddfSDavid du Colombier 		}
21797dd7cddfSDavid du Colombier 
21809a747e4fSDavid du Colombier 		syslog(0, LOG, ": remote=%I vlen %d proto %d response user %s nresp %d", ppp->remote, vlen, c->proto, c->cs->user, c->cs->nresp);
21819a747e4fSDavid du Colombier 		if((ai = auth_response(c->cs)) == nil || auth_chuid(ai, nil) < 0){
21827dd7cddfSDavid du Colombier 			c->state = Cunauth;
21837dd7cddfSDavid du Colombier 			code = Cfailure;
21849a747e4fSDavid du Colombier 			syslog(0, LOG, ": remote=%I: auth failed: %r, uid=%s", ppp->remote, uid);
21857dd7cddfSDavid du Colombier 		}else{
21867dd7cddfSDavid du Colombier 			c->state = Cauthok;
21877dd7cddfSDavid du Colombier 			code = Csuccess;
21889a747e4fSDavid du Colombier 			syslog(0, LOG, ": remote=%I: auth ok: uid=%s nsecret=%d", ppp->remote, uid, ai->nsecret);
21899a747e4fSDavid du Colombier 			if(c->proto == APmschap){
21909a747e4fSDavid du Colombier 				if(ai->nsecret != sizeof(ppp->key))
21917dd7cddfSDavid du Colombier 					sysfatal("could not get the encryption key");
21929a747e4fSDavid du Colombier 				memmove(ppp->key, ai->secret, sizeof(ppp->key));
21937dd7cddfSDavid du Colombier 			}
21949a747e4fSDavid du Colombier 		}
21959a747e4fSDavid du Colombier 		auth_freeAI(ai);
21969a747e4fSDavid du Colombier 		auth_freechal(c->cs);
21979a747e4fSDavid du Colombier 		c->cs = nil;
21987dd7cddfSDavid du Colombier 		freeb(b);
21997dd7cddfSDavid du Colombier 
22007dd7cddfSDavid du Colombier 		/* send reply */
22017dd7cddfSDavid du Colombier 		len = 4;
22027dd7cddfSDavid du Colombier 		b = alloclcp(code, c->id, len, &m);
22037dd7cddfSDavid du Colombier 		hnputs(m->len, len);
22047dd7cddfSDavid du Colombier 		putframe(ppp, Pchap, b);
22057dd7cddfSDavid du Colombier 
22067dd7cddfSDavid du Colombier 		if(c->state == Cauthok) {
22077dd7cddfSDavid du Colombier 			setphase(ppp, Pnet);
22087dd7cddfSDavid du Colombier 		} else {
22097dd7cddfSDavid du Colombier 			/* restart chapp negotiation */
22107dd7cddfSDavid du Colombier 			chapinit(ppp);
22117dd7cddfSDavid du Colombier 		}
22127dd7cddfSDavid du Colombier 
22137dd7cddfSDavid du Colombier 		break;
22147dd7cddfSDavid du Colombier 	case Csuccess:
22157dd7cddfSDavid du Colombier 		netlog("ppp: chap succeeded\n");
22167dd7cddfSDavid du Colombier 		break;
22177dd7cddfSDavid du Colombier 	case Cfailure:
221859cc4ca5SDavid du Colombier 		netlog("ppp: chap failed\n");
22197dd7cddfSDavid du Colombier 		break;
22207dd7cddfSDavid du Colombier 	default:
22217dd7cddfSDavid du Colombier 		syslog(0, LOG, "chap code %d?\n", m->code);
22227dd7cddfSDavid du Colombier 		break;
22237dd7cddfSDavid du Colombier 	}
22247dd7cddfSDavid du Colombier 	qunlock(ppp);
22257dd7cddfSDavid du Colombier 	freeb(b);
22267dd7cddfSDavid du Colombier }
22277dd7cddfSDavid du Colombier 
22287dd7cddfSDavid du Colombier static void
putpaprequest(PPP * ppp)222980ee5cbfSDavid du Colombier putpaprequest(PPP *ppp)
223080ee5cbfSDavid du Colombier {
223180ee5cbfSDavid du Colombier 	Block *b;
223280ee5cbfSDavid du Colombier 	Lcpmsg *m;
223380ee5cbfSDavid du Colombier 	Chap *c;
223480ee5cbfSDavid du Colombier 	int len, nlen, slen;
223580ee5cbfSDavid du Colombier 
2236dc5a79c1SDavid du Colombier 	getauth(ppp);
2237dc5a79c1SDavid du Colombier 
223880ee5cbfSDavid du Colombier 	c = ppp->chap;
223980ee5cbfSDavid du Colombier 	c->id++;
224080ee5cbfSDavid du Colombier 	netlog("PPP: pap: send authreq %d %s %s\n", c->id, ppp->chapname, "****");
224180ee5cbfSDavid du Colombier 
224280ee5cbfSDavid du Colombier 	nlen = strlen(ppp->chapname);
224380ee5cbfSDavid du Colombier 	slen = strlen(ppp->secret);
224480ee5cbfSDavid du Colombier 	len = 4 + 1 + nlen + 1 + slen;
224580ee5cbfSDavid du Colombier 	b = alloclcp(Pauthreq, c->id, len, &m);
224680ee5cbfSDavid du Colombier 
224780ee5cbfSDavid du Colombier 	*b->wptr++ = nlen;
224880ee5cbfSDavid du Colombier 	memmove(b->wptr, ppp->chapname, nlen);
224980ee5cbfSDavid du Colombier 	b->wptr += nlen;
225080ee5cbfSDavid du Colombier 	*b->wptr++ = slen;
225180ee5cbfSDavid du Colombier 	memmove(b->wptr, ppp->secret, slen);
225280ee5cbfSDavid du Colombier 	b->wptr += slen;
225380ee5cbfSDavid du Colombier 	hnputs(m->len, len);
225480ee5cbfSDavid du Colombier 
225580ee5cbfSDavid du Colombier 	putframe(ppp, Ppasswd, b);
225680ee5cbfSDavid du Colombier 	freeb(b);
225780ee5cbfSDavid du Colombier }
225880ee5cbfSDavid du Colombier 
225980ee5cbfSDavid du Colombier static void
papinit(PPP * ppp)226080ee5cbfSDavid du Colombier papinit(PPP *ppp)
226180ee5cbfSDavid du Colombier {
226280ee5cbfSDavid du Colombier 	ppp->chap->id = 0;
226380ee5cbfSDavid du Colombier 	putpaprequest(ppp);
226480ee5cbfSDavid du Colombier }
226580ee5cbfSDavid du Colombier 
226680ee5cbfSDavid du Colombier static void
getpap(PPP * ppp,Block * b)226780ee5cbfSDavid du Colombier getpap(PPP *ppp, Block *b)
226880ee5cbfSDavid du Colombier {
226980ee5cbfSDavid du Colombier 	Lcpmsg *m;
227080ee5cbfSDavid du Colombier 	int len;
227180ee5cbfSDavid du Colombier 
227280ee5cbfSDavid du Colombier 	m = (Lcpmsg*)b->rptr;
227380ee5cbfSDavid du Colombier 	len = 4;
227480ee5cbfSDavid du Colombier 	if(BLEN(b) < 4 || BLEN(b) < (len = nhgets(m->len))){
227580ee5cbfSDavid du Colombier 		syslog(0, LOG, "short pap message (%ld < %d)", BLEN(b), len);
227680ee5cbfSDavid du Colombier 		freeb(b);
227780ee5cbfSDavid du Colombier 		return;
227880ee5cbfSDavid du Colombier 	}
227980ee5cbfSDavid du Colombier 	if(len < sizeof(Lcpmsg))
228080ee5cbfSDavid du Colombier 		m->data[0] = 0;
228180ee5cbfSDavid du Colombier 
228280ee5cbfSDavid du Colombier 	qlock(ppp);
228380ee5cbfSDavid du Colombier 	switch(m->code){
228480ee5cbfSDavid du Colombier 	case Pauthreq:
228580ee5cbfSDavid du Colombier 		netlog("PPP: pap auth request, not supported\n");
228680ee5cbfSDavid du Colombier 		break;
228780ee5cbfSDavid du Colombier 	case Pauthack:
228880ee5cbfSDavid du Colombier 		if(ppp->phase == Pauth
228980ee5cbfSDavid du Colombier 		&& ppp->chap->proto == APpasswd
229080ee5cbfSDavid du Colombier 		&& m->id <= ppp-> chap->id){
229180ee5cbfSDavid du Colombier 			netlog("PPP: pap succeeded\n");
229280ee5cbfSDavid du Colombier 			setphase(ppp, Pnet);
229380ee5cbfSDavid du Colombier 		}
229480ee5cbfSDavid du Colombier 		break;
229580ee5cbfSDavid du Colombier 	case Pauthnak:
229680ee5cbfSDavid du Colombier 		if(ppp->phase == Pauth
229780ee5cbfSDavid du Colombier 		&& ppp->chap->proto == APpasswd
229880ee5cbfSDavid du Colombier 		&& m->id <= ppp-> chap->id){
229980ee5cbfSDavid du Colombier 			netlog("PPP: pap failed (%d:%.*s)\n",
230080ee5cbfSDavid du Colombier 				m->data[0], m->data[0], (char*)m->data+1);
230180ee5cbfSDavid du Colombier 			terminate(ppp, 0);
230280ee5cbfSDavid du Colombier 		}
230380ee5cbfSDavid du Colombier 		break;
230480ee5cbfSDavid du Colombier 	default:
230580ee5cbfSDavid du Colombier 		netlog("PPP: unknown pap messsage %d\n", m->code);
230680ee5cbfSDavid du Colombier 	}
230780ee5cbfSDavid du Colombier 	qunlock(ppp);
230880ee5cbfSDavid du Colombier 	freeb(b);
230980ee5cbfSDavid du Colombier }
231080ee5cbfSDavid du Colombier 
231180ee5cbfSDavid du Colombier static void
printopts(Pstate * p,Block * b,int send)23127dd7cddfSDavid du Colombier printopts(Pstate *p, Block *b, int send)
23137dd7cddfSDavid du Colombier {
23147dd7cddfSDavid du Colombier 	Lcpmsg *m;
23157dd7cddfSDavid du Colombier 	Lcpopt *o;
23167dd7cddfSDavid du Colombier 	int proto, x, period;
23177dd7cddfSDavid du Colombier 	uchar *cp;
23187dd7cddfSDavid du Colombier 	char *code, *dir;
23197dd7cddfSDavid du Colombier 
23207dd7cddfSDavid du Colombier 	m = (Lcpmsg*)b->rptr;
23217dd7cddfSDavid du Colombier 	switch(m->code) {
23227dd7cddfSDavid du Colombier 	default: code = "<unknown>"; break;
23237dd7cddfSDavid du Colombier 	case Lconfreq: code = "confrequest"; break;
23247dd7cddfSDavid du Colombier 	case Lconfack: code = "confack"; break;
23257dd7cddfSDavid du Colombier 	case Lconfnak: code = "confnak"; break;
23267dd7cddfSDavid du Colombier 	case Lconfrej: code = "confreject"; break;
23277dd7cddfSDavid du Colombier 	}
23287dd7cddfSDavid du Colombier 
23297dd7cddfSDavid du Colombier 	if(send)
23307dd7cddfSDavid du Colombier 		dir = "send";
23317dd7cddfSDavid du Colombier 	else
23327dd7cddfSDavid du Colombier 		dir = "recv";
23337dd7cddfSDavid du Colombier 
23347dd7cddfSDavid du Colombier 	netlog("ppp: %s %s: id=%d\n", dir, code, m->id);
23357dd7cddfSDavid du Colombier 
23367dd7cddfSDavid du Colombier 	for(cp = m->data; cp < b->wptr; cp += o->len){
23377dd7cddfSDavid du Colombier 		o = (Lcpopt*)cp;
23387dd7cddfSDavid du Colombier 		if(cp + o->len > b->wptr){
23397dd7cddfSDavid du Colombier 			netlog("\tbad option length %ux\n", o->type);
23407dd7cddfSDavid du Colombier 			return;
23417dd7cddfSDavid du Colombier 		}
23427dd7cddfSDavid du Colombier 
23437dd7cddfSDavid du Colombier 		switch(p->proto){
23447dd7cddfSDavid du Colombier 		case Plcp:
23457dd7cddfSDavid du Colombier 			switch(o->type){
23467dd7cddfSDavid du Colombier 			default:
23477dd7cddfSDavid du Colombier 				netlog("\tunknown %d len=%d\n", o->type, o->len);
23487dd7cddfSDavid du Colombier 				break;
23497dd7cddfSDavid du Colombier 			case Omtu:
23507dd7cddfSDavid du Colombier 				netlog("\tmtu = %d\n", nhgets(o->data));
23517dd7cddfSDavid du Colombier 				break;
23527dd7cddfSDavid du Colombier 			case Octlmap:
23537dd7cddfSDavid du Colombier 				netlog("\tctlmap = %ux\n", nhgetl(o->data));
23547dd7cddfSDavid du Colombier 				break;
23557dd7cddfSDavid du Colombier 			case Oauth:
235659cc4ca5SDavid du Colombier 				netlog("\tauth = %ux", nhgetl(o->data));
23577dd7cddfSDavid du Colombier 				proto = nhgets(o->data);
23587dd7cddfSDavid du Colombier 				switch(proto) {
23597dd7cddfSDavid du Colombier 				default:
23607dd7cddfSDavid du Colombier 					netlog("unknown auth proto %d\n", proto);
23617dd7cddfSDavid du Colombier 					break;
23627dd7cddfSDavid du Colombier 				case Ppasswd:
23637dd7cddfSDavid du Colombier 					netlog("password\n");
23647dd7cddfSDavid du Colombier 					break;
23657dd7cddfSDavid du Colombier 				case Pchap:
23667dd7cddfSDavid du Colombier 					netlog("chap %ux\n", o->data[2]);
23677dd7cddfSDavid du Colombier 					break;
23687dd7cddfSDavid du Colombier 				}
23697dd7cddfSDavid du Colombier 				break;
23707dd7cddfSDavid du Colombier 			case Oquality:
23717dd7cddfSDavid du Colombier 				proto = nhgets(o->data);
23727dd7cddfSDavid du Colombier 				switch(proto) {
23737dd7cddfSDavid du Colombier 				default:
23747dd7cddfSDavid du Colombier 					netlog("\tunknown quality proto %d\n", proto);
23757dd7cddfSDavid du Colombier 					break;
23767dd7cddfSDavid du Colombier 				case Plqm:
23777dd7cddfSDavid du Colombier 					x = nhgetl(o->data+2)*10;
23787dd7cddfSDavid du Colombier 					period = (x+Period-1)/Period;
23797dd7cddfSDavid du Colombier 					netlog("\tlqm period = %d\n", period);
23807dd7cddfSDavid du Colombier 					break;
23817dd7cddfSDavid du Colombier 				}
23827dd7cddfSDavid du Colombier 			case Omagic:
23837dd7cddfSDavid du Colombier 				netlog("\tmagic = %ux\n", nhgetl(o->data));
23847dd7cddfSDavid du Colombier 				break;
23857dd7cddfSDavid du Colombier 			case Opc:
23867dd7cddfSDavid du Colombier 				netlog("\tprotocol compress\n");
23877dd7cddfSDavid du Colombier 				break;
23887dd7cddfSDavid du Colombier 			case Oac:
23897dd7cddfSDavid du Colombier 				netlog("\taddr compress\n");
23907dd7cddfSDavid du Colombier 				break;
23917dd7cddfSDavid du Colombier 			}
23927dd7cddfSDavid du Colombier 			break;
23937dd7cddfSDavid du Colombier 		case Pccp:
23947dd7cddfSDavid du Colombier 			switch(o->type){
23957dd7cddfSDavid du Colombier 			default:
23967dd7cddfSDavid du Colombier 				netlog("\tunknown %d len=%d\n", o->type, o->len);
23977dd7cddfSDavid du Colombier 				break;
23987dd7cddfSDavid du Colombier 			case Ocoui:
23997dd7cddfSDavid du Colombier 				netlog("\tOUI\n");
24007dd7cddfSDavid du Colombier 				break;
24017dd7cddfSDavid du Colombier 			case Ocstac:
24027dd7cddfSDavid du Colombier 				netlog("\tstac LZS\n");
24037dd7cddfSDavid du Colombier 				break;
24047dd7cddfSDavid du Colombier 			case Ocmppc:
24057dd7cddfSDavid du Colombier 				netlog("\tMicrosoft PPC len=%d %ux\n", o->len, nhgetl(o->data));
24067dd7cddfSDavid du Colombier 				break;
24077dd7cddfSDavid du Colombier 			case Octhwack:
24087dd7cddfSDavid du Colombier 				netlog("\tThwack\n");
24097dd7cddfSDavid du Colombier 				break;
24107dd7cddfSDavid du Colombier 			}
24117dd7cddfSDavid du Colombier 			break;
24127dd7cddfSDavid du Colombier 		case Pecp:
24137dd7cddfSDavid du Colombier 			switch(o->type){
24147dd7cddfSDavid du Colombier 			default:
24157dd7cddfSDavid du Colombier 				netlog("\tunknown %d len=%d\n", o->type, o->len);
24167dd7cddfSDavid du Colombier 				break;
24177dd7cddfSDavid du Colombier 			case Oeoui:
24187dd7cddfSDavid du Colombier 				netlog("\tOUI\n");
24197dd7cddfSDavid du Colombier 				break;
24207dd7cddfSDavid du Colombier 			case Oedese:
24217dd7cddfSDavid du Colombier 				netlog("\tDES\n");
24227dd7cddfSDavid du Colombier 				break;
24237dd7cddfSDavid du Colombier 			}
24247dd7cddfSDavid du Colombier 			break;
24257dd7cddfSDavid du Colombier 		case Pipcp:
24267dd7cddfSDavid du Colombier 			switch(o->type){
24277dd7cddfSDavid du Colombier 			default:
24287dd7cddfSDavid du Colombier 				netlog("\tunknown %d len=%d\n", o->type, o->len);
24297dd7cddfSDavid du Colombier 				break;
24307dd7cddfSDavid du Colombier 			case Oipaddrs:
24317dd7cddfSDavid du Colombier 				netlog("\tip addrs - deprecated\n");
24327dd7cddfSDavid du Colombier 				break;
24337dd7cddfSDavid du Colombier 			case Oipcompress:
24347dd7cddfSDavid du Colombier 				netlog("\tip compress\n");
24357dd7cddfSDavid du Colombier 				break;
24367dd7cddfSDavid du Colombier 			case Oipaddr:
24377dd7cddfSDavid du Colombier 				netlog("\tip addr %V\n", o->data);
24387dd7cddfSDavid du Colombier 				break;
24397dd7cddfSDavid du Colombier 			case Oipdns:
24407dd7cddfSDavid du Colombier 				netlog("\tdns addr %V\n", o->data);
24417dd7cddfSDavid du Colombier 				break;
24427dd7cddfSDavid du Colombier 			case Oipwins:
24437dd7cddfSDavid du Colombier 				netlog("\twins addr %V\n", o->data);
24447dd7cddfSDavid du Colombier 				break;
24457dd7cddfSDavid du Colombier 			case Oipdns2:
24467dd7cddfSDavid du Colombier 				netlog("\tdns2 addr %V\n", o->data);
24477dd7cddfSDavid du Colombier 				break;
24487dd7cddfSDavid du Colombier 			case Oipwins2:
24497dd7cddfSDavid du Colombier 				netlog("\twins2 addr %V\n", o->data);
24507dd7cddfSDavid du Colombier 				break;
24517dd7cddfSDavid du Colombier 			}
24527dd7cddfSDavid du Colombier 			break;
24537dd7cddfSDavid du Colombier 		}
24547dd7cddfSDavid du Colombier 	}
24557dd7cddfSDavid du Colombier }
24567dd7cddfSDavid du Colombier 
24577dd7cddfSDavid du Colombier static void
sendtermreq(PPP * ppp,Pstate * p)24587dd7cddfSDavid du Colombier sendtermreq(PPP *ppp, Pstate *p)
24597dd7cddfSDavid du Colombier {
24607dd7cddfSDavid du Colombier 	Block *b;
24617dd7cddfSDavid du Colombier 	Lcpmsg *m;
24627dd7cddfSDavid du Colombier 
24637dd7cddfSDavid du Colombier 	p->termid = ++(p->id);
24647dd7cddfSDavid du Colombier 	b = alloclcp(Ltermreq, p->termid, 4, &m);
24657dd7cddfSDavid du Colombier 	hnputs(m->len, 4);
24667dd7cddfSDavid du Colombier 	putframe(ppp, p->proto, b);
24677dd7cddfSDavid du Colombier 	freeb(b);
24687dd7cddfSDavid du Colombier 	newstate(ppp, p, Sclosing);
24697dd7cddfSDavid du Colombier }
24707dd7cddfSDavid du Colombier 
24717dd7cddfSDavid du Colombier static void
sendechoreq(PPP * ppp,Pstate * p)24727dd7cddfSDavid du Colombier sendechoreq(PPP *ppp, Pstate *p)
24737dd7cddfSDavid du Colombier {
24747dd7cddfSDavid du Colombier 	Block *b;
24757dd7cddfSDavid du Colombier 	Lcpmsg *m;
24767dd7cddfSDavid du Colombier 
24777dd7cddfSDavid du Colombier 	p->termid = ++(p->id);
24787dd7cddfSDavid du Colombier 	b = alloclcp(Lechoreq, p->id, 4, &m);
24797dd7cddfSDavid du Colombier 	hnputs(m->len, 4);
24807dd7cddfSDavid du Colombier 	putframe(ppp, p->proto, b);
24817dd7cddfSDavid du Colombier 	freeb(b);
24827dd7cddfSDavid du Colombier }
24837dd7cddfSDavid du Colombier 
24847dd7cddfSDavid du Colombier enum
24857dd7cddfSDavid du Colombier {
24867dd7cddfSDavid du Colombier 	CtrlD	= 0x4,
24877dd7cddfSDavid du Colombier 	CtrlE	= 0x5,
24887dd7cddfSDavid du Colombier 	CtrlO	= 0xf,
24897dd7cddfSDavid du Colombier 	Cr	= 13,
24907dd7cddfSDavid du Colombier 	View	= 0x80,
24917dd7cddfSDavid du Colombier };
24927dd7cddfSDavid du Colombier 
24937dd7cddfSDavid du Colombier int conndone;
24947dd7cddfSDavid du Colombier 
24957dd7cddfSDavid du Colombier static void
xfer(int fd)24967dd7cddfSDavid du Colombier xfer(int fd)
24977dd7cddfSDavid du Colombier {
24987dd7cddfSDavid du Colombier 	int i, n;
24997dd7cddfSDavid du Colombier 	uchar xbuf[128];
25007dd7cddfSDavid du Colombier 
25017dd7cddfSDavid du Colombier 	for(;;) {
25027dd7cddfSDavid du Colombier 		n = read(fd, xbuf, sizeof(xbuf));
25037dd7cddfSDavid du Colombier 		if(n < 0)
25047dd7cddfSDavid du Colombier 			break;
25057dd7cddfSDavid du Colombier 		if(conndone)
25067dd7cddfSDavid du Colombier 			break;
25077dd7cddfSDavid du Colombier 		for(i = 0; i < n; i++)
25087dd7cddfSDavid du Colombier 			if(xbuf[i] == Cr)
25097dd7cddfSDavid du Colombier 				xbuf[i] = ' ';
25107dd7cddfSDavid du Colombier 		write(1, xbuf, n);
25117dd7cddfSDavid du Colombier 	}
25127dd7cddfSDavid du Colombier 	close(fd);
25137dd7cddfSDavid du Colombier }
25147dd7cddfSDavid du Colombier 
251539734e7eSDavid du Colombier static int
readcr(int fd,char * buf,int nbuf)251639734e7eSDavid du Colombier readcr(int fd, char *buf, int nbuf)
251739734e7eSDavid du Colombier {
251839734e7eSDavid du Colombier 	char c;
251939734e7eSDavid du Colombier 	int n, tot;
252039734e7eSDavid du Colombier 
252139734e7eSDavid du Colombier 	tot = 0;
252239734e7eSDavid du Colombier 	while((n=read(fd, &c, 1)) == 1){
252339734e7eSDavid du Colombier 		if(c == '\n'){
252439734e7eSDavid du Colombier 			buf[tot] = 0;
252539734e7eSDavid du Colombier 			return tot;
252639734e7eSDavid du Colombier 		}
252739734e7eSDavid du Colombier 		buf[tot++] = c;
252839734e7eSDavid du Colombier 		if(tot == nbuf)
252939734e7eSDavid du Colombier 			sysfatal("line too long in readcr");
253039734e7eSDavid du Colombier 	}
253139734e7eSDavid du Colombier 	return n;
253239734e7eSDavid du Colombier }
253339734e7eSDavid du Colombier 
25347dd7cddfSDavid du Colombier static void
connect(int fd,int cfd)25357dd7cddfSDavid du Colombier connect(int fd, int cfd)
25367dd7cddfSDavid du Colombier {
25377dd7cddfSDavid du Colombier 	int n, ctl;
25387dd7cddfSDavid du Colombier 	char xbuf[128];
25397dd7cddfSDavid du Colombier 
25403ff48bf5SDavid du Colombier 	if (chatfile) {
25413ff48bf5SDavid du Colombier 		int chatfd, lineno, nb;
25423ff48bf5SDavid du Colombier 		char *buf, *p, *s, response[128];
25433ff48bf5SDavid du Colombier 		Dir *dir;
25443ff48bf5SDavid du Colombier 
25453ff48bf5SDavid du Colombier 		if ((chatfd = open(chatfile, OREAD)) < 0)
25463ff48bf5SDavid du Colombier 			sysfatal("cannot open %s: %r", chatfile);
25473ff48bf5SDavid du Colombier 
25483ff48bf5SDavid du Colombier 		if ((dir = dirfstat(chatfd)) == nil)
25493ff48bf5SDavid du Colombier 			sysfatal("cannot fstat %s: %r",chatfile);
25503ff48bf5SDavid du Colombier 
25513ff48bf5SDavid du Colombier 		buf = (char *)malloc(dir->length + 1);
25523ff48bf5SDavid du Colombier 		assert(buf);
25533ff48bf5SDavid du Colombier 
25543ff48bf5SDavid du Colombier 		if ((nb = read(chatfd, buf, dir->length)) < 0)
25553ff48bf5SDavid du Colombier 			sysfatal("cannot read chatfile %s: %r", chatfile);
25563ff48bf5SDavid du Colombier 		assert(nb == dir->length);
25573ff48bf5SDavid du Colombier 		buf[dir->length] = '\0';
25583ff48bf5SDavid du Colombier 		free(dir);
25593ff48bf5SDavid du Colombier 		close(chatfd);
25603ff48bf5SDavid du Colombier 
25613ff48bf5SDavid du Colombier 		p = buf;
25623ff48bf5SDavid du Colombier 		lineno = 0;
2563eed6406fSDavid du Colombier 		for(;;) {
25643ff48bf5SDavid du Colombier 			char *_args[3];
25653ff48bf5SDavid du Colombier 
25663ff48bf5SDavid du Colombier 			if ((s = strchr(p, '\n')) == nil)
25673ff48bf5SDavid du Colombier 				break;
25683ff48bf5SDavid du Colombier 			*s++ = '\0';
25693ff48bf5SDavid du Colombier 
25703ff48bf5SDavid du Colombier 			lineno++;
25713ff48bf5SDavid du Colombier 
25723ff48bf5SDavid du Colombier 			if (*p == '#') {
25733ff48bf5SDavid du Colombier 				p = s;
25743ff48bf5SDavid du Colombier 				continue;
25753ff48bf5SDavid du Colombier 			}
25763ff48bf5SDavid du Colombier 
25773ff48bf5SDavid du Colombier 			if (tokenize(p, _args, 3) != 2)
25783ff48bf5SDavid du Colombier 				sysfatal("invalid line %d (line expected: 'send' 'expect')",
25793ff48bf5SDavid du Colombier 						lineno);
25803ff48bf5SDavid du Colombier 
25813ff48bf5SDavid du Colombier 			if (debug)
25823ff48bf5SDavid du Colombier 				print("sending %s, expecting %s\n", _args[0], _args[1]);
25833ff48bf5SDavid du Colombier 
258439734e7eSDavid du Colombier 			if(strlen(_args[0])){
258539734e7eSDavid du Colombier 				nb = fprint(fd, "%s\r", _args[0]);
258639734e7eSDavid du Colombier 				assert(nb > 0);
258739734e7eSDavid du Colombier 			}
25883ff48bf5SDavid du Colombier 
25893ff48bf5SDavid du Colombier 			if (strlen(_args[1]) > 0) {
259039734e7eSDavid du Colombier 				if ((nb = readcr(fd, response, sizeof response-1)) < 0)
25913ff48bf5SDavid du Colombier 					sysfatal("cannot read response from: %r");
25923ff48bf5SDavid du Colombier 
25933ff48bf5SDavid du Colombier 				if (debug)
25943ff48bf5SDavid du Colombier 					print("response %s\n", response);
25953ff48bf5SDavid du Colombier 
25963ff48bf5SDavid du Colombier 				if (nb == 0)
259714cc0f53SDavid du Colombier 					sysfatal("eof on input?");
25983ff48bf5SDavid du Colombier 
25993ff48bf5SDavid du Colombier 				if (cistrstr(response, _args[1]) == nil)
260014cc0f53SDavid du Colombier 					sysfatal("expected %s, got %s", _args[1], response);
26013ff48bf5SDavid du Colombier 			}
26023ff48bf5SDavid du Colombier 			p = s;
26033ff48bf5SDavid du Colombier 		}
26043ff48bf5SDavid du Colombier 		free(buf);
26053ff48bf5SDavid du Colombier 		return;
26063ff48bf5SDavid du Colombier 	}
26073ff48bf5SDavid du Colombier 
26087dd7cddfSDavid du Colombier 	print("Connect to file system now, type ctrl-d when done.\n");
26097dd7cddfSDavid du Colombier 	print("...(Use the view or down arrow key to send a break)\n");
26107dd7cddfSDavid du Colombier 	print("...(Use ctrl-e to set even parity or ctrl-o for odd)\n");
26117dd7cddfSDavid du Colombier 
26127dd7cddfSDavid du Colombier 	ctl = open("/dev/consctl", OWRITE);
26137dd7cddfSDavid du Colombier 	if(ctl < 0)
26147dd7cddfSDavid du Colombier 		sysfatal("opening consctl");
26157dd7cddfSDavid du Colombier 	fprint(ctl, "rawon");
26167dd7cddfSDavid du Colombier 
26177dd7cddfSDavid du Colombier 	fd = dup(fd, -1);
26187dd7cddfSDavid du Colombier 	conndone = 0;
26197dd7cddfSDavid du Colombier 	switch(rfork(RFPROC|RFMEM|RFNOWAIT)){
26207dd7cddfSDavid du Colombier 	case -1:
26217dd7cddfSDavid du Colombier 		sysfatal("forking xfer");
26227dd7cddfSDavid du Colombier 	case 0:
26237dd7cddfSDavid du Colombier 		xfer(fd);
26247dd7cddfSDavid du Colombier 		_exits(nil);
26257dd7cddfSDavid du Colombier 	}
26267dd7cddfSDavid du Colombier 
26277dd7cddfSDavid du Colombier 	for(;;){
26287dd7cddfSDavid du Colombier 		read(0, xbuf, 1);
26297dd7cddfSDavid du Colombier 		switch(xbuf[0]&0xff) {
26307dd7cddfSDavid du Colombier 		case CtrlD:	/* done */
26317dd7cddfSDavid du Colombier 			conndone = 1;
26327dd7cddfSDavid du Colombier 			close(ctl);
26337dd7cddfSDavid du Colombier 			print("\n");
26347dd7cddfSDavid du Colombier 			return;
26357dd7cddfSDavid du Colombier 		case CtrlE:	/* set even parity */
26367dd7cddfSDavid du Colombier 			fprint(cfd, "pe");
26377dd7cddfSDavid du Colombier 			break;
26387dd7cddfSDavid du Colombier 		case CtrlO:	/* set odd parity */
26397dd7cddfSDavid du Colombier 			fprint(cfd, "po");
26407dd7cddfSDavid du Colombier 			break;
26417dd7cddfSDavid du Colombier 		case View:	/* send a break */
26427dd7cddfSDavid du Colombier 			fprint(cfd, "k500");
26437dd7cddfSDavid du Colombier 			break;
26447dd7cddfSDavid du Colombier 		default:
26457dd7cddfSDavid du Colombier 			n = write(fd, xbuf, 1);
26467dd7cddfSDavid du Colombier 			if(n < 0) {
26479a747e4fSDavid du Colombier 				errstr(xbuf, sizeof(xbuf));
26487dd7cddfSDavid du Colombier 				conndone = 1;
26497dd7cddfSDavid du Colombier 				close(ctl);
26507dd7cddfSDavid du Colombier 				print("[remote write error (%s)]\n", xbuf);
26517dd7cddfSDavid du Colombier 				return;
26527dd7cddfSDavid du Colombier 			}
26537dd7cddfSDavid du Colombier 		}
26547dd7cddfSDavid du Colombier 	}
26557dd7cddfSDavid du Colombier }
26567dd7cddfSDavid du Colombier 
26577dd7cddfSDavid du Colombier int interactive;
26587dd7cddfSDavid du Colombier 
26597dd7cddfSDavid du Colombier void
usage(void)26607dd7cddfSDavid du Colombier usage(void)
26617dd7cddfSDavid du Colombier {
2662*4f81ea25SDavid du Colombier 	fprint(2, "usage: ppp [-CPSacdfu] [-b baud] [-k keyspec] [-m mtu] "
2663*4f81ea25SDavid du Colombier 		"[-M chatfile] [-p dev] [-x netmntpt] [-t modemcmd] "
2664*4f81ea25SDavid du Colombier 		"[local-addr [remote-addr]]\n");
26657dd7cddfSDavid du Colombier 	exits("usage");
26667dd7cddfSDavid du Colombier }
26677dd7cddfSDavid du Colombier 
26687dd7cddfSDavid du Colombier void
main(int argc,char ** argv)26697dd7cddfSDavid du Colombier main(int argc, char **argv)
26707dd7cddfSDavid du Colombier {
2671d9306527SDavid du Colombier 	int mtu, baud, framing, user, mediain, mediaout, cfd;
26727dd7cddfSDavid du Colombier 	Ipaddr ipaddr, remip;
2673bedadc12SDavid du Colombier 	char *dev, *modemcmd;
26747dd7cddfSDavid du Colombier 	char net[128];
26757dd7cddfSDavid du Colombier 	PPP *ppp;
26767dd7cddfSDavid du Colombier 	char buf[128];
26777dd7cddfSDavid du Colombier 
26786b6b9ac8SDavid du Colombier 	rfork(RFREND|RFNOTEG|RFNAMEG);
26797dd7cddfSDavid du Colombier 
26809a747e4fSDavid du Colombier 	fmtinstall('I', eipfmt);
26819a747e4fSDavid du Colombier 	fmtinstall('V', eipfmt);
26829a747e4fSDavid du Colombier 	fmtinstall('E', eipfmt);
26837dd7cddfSDavid du Colombier 
26847dd7cddfSDavid du Colombier 	dev = nil;
26857dd7cddfSDavid du Colombier 
26867dd7cddfSDavid du Colombier 	invalidate(ipaddr);
26877dd7cddfSDavid du Colombier 	invalidate(remip);
26887dd7cddfSDavid du Colombier 
26897dd7cddfSDavid du Colombier 	mtu = Defmtu;
26907dd7cddfSDavid du Colombier 	baud = 0;
26917dd7cddfSDavid du Colombier 	framing = 0;
26927dd7cddfSDavid du Colombier 	setnetmtpt(net, sizeof(net), nil);
26937dd7cddfSDavid du Colombier 	user = 0;
26947dd7cddfSDavid du Colombier 	modemcmd = nil;
26957dd7cddfSDavid du Colombier 
26967dd7cddfSDavid du Colombier 	ARGBEGIN{
2697*4f81ea25SDavid du Colombier 	case 'a':
2698*4f81ea25SDavid du Colombier 		noauth = 1;
2699*4f81ea25SDavid du Colombier 		break;
27007dd7cddfSDavid du Colombier 	case 'b':
2701bedadc12SDavid du Colombier 		baud = atoi(EARGF(usage()));
27027dd7cddfSDavid du Colombier 		if(baud < 0)
27037dd7cddfSDavid du Colombier 			baud = 0;
27047dd7cddfSDavid du Colombier 		break;
270559cc4ca5SDavid du Colombier 	case 'c':
270659cc4ca5SDavid du Colombier 		nocompress = 1;
270759cc4ca5SDavid du Colombier 		break;
270859cc4ca5SDavid du Colombier 	case 'C':
270959cc4ca5SDavid du Colombier 		noipcompress = 1;
271059cc4ca5SDavid du Colombier 		break;
271159cc4ca5SDavid du Colombier 	case 'd':
271259cc4ca5SDavid du Colombier 		debug++;
271359cc4ca5SDavid du Colombier 		break;
271459cc4ca5SDavid du Colombier 	case 'f':
271559cc4ca5SDavid du Colombier 		framing = 1;
271659cc4ca5SDavid du Colombier 		break;
27179a747e4fSDavid du Colombier 	case 'F':
27189a747e4fSDavid du Colombier 		pppframing = 0;
27199a747e4fSDavid du Colombier 		break;
2720bedadc12SDavid du Colombier 	case 'k':
2721bedadc12SDavid du Colombier 		keyspec = EARGF(usage());
2722bedadc12SDavid du Colombier 		break;
27237dd7cddfSDavid du Colombier 	case 'm':
2724bedadc12SDavid du Colombier 		mtu = atoi(EARGF(usage()));
27257dd7cddfSDavid du Colombier 		if(mtu < Minmtu)
27267dd7cddfSDavid du Colombier 			mtu = Minmtu;
27277dd7cddfSDavid du Colombier 		if(mtu > Maxmtu)
27287dd7cddfSDavid du Colombier 			mtu = Maxmtu;
27297dd7cddfSDavid du Colombier 		break;
27303ff48bf5SDavid du Colombier 	case 'M':
27313ff48bf5SDavid du Colombier 		chatfile = EARGF(usage());
27323ff48bf5SDavid du Colombier 		break;
27337dd7cddfSDavid du Colombier 	case 'p':
2734bedadc12SDavid du Colombier 		dev = EARGF(usage());
27357dd7cddfSDavid du Colombier 		break;
273659cc4ca5SDavid du Colombier 	case 'P':
273759cc4ca5SDavid du Colombier 		primary = 1;
27387dd7cddfSDavid du Colombier 		break;
27397dd7cddfSDavid du Colombier 	case 'S':
27407dd7cddfSDavid du Colombier 		server = 1;
27417dd7cddfSDavid du Colombier 		break;
27427dd7cddfSDavid du Colombier 	case 't':
2743bedadc12SDavid du Colombier 		modemcmd = EARGF(usage());
27447dd7cddfSDavid du Colombier 		break;
274559cc4ca5SDavid du Colombier 	case 'u':
274659cc4ca5SDavid du Colombier 		user = 1;
274759cc4ca5SDavid du Colombier 		break;
274859cc4ca5SDavid du Colombier 	case 'x':
2749bedadc12SDavid du Colombier 		setnetmtpt(net, sizeof net, EARGF(usage()));
275059cc4ca5SDavid du Colombier 		break;
27517dd7cddfSDavid du Colombier 	default:
2752bedadc12SDavid du Colombier 		fprint(2, "unknown option %c\n", ARGC());
2753bedadc12SDavid du Colombier 		usage();
27547dd7cddfSDavid du Colombier 	}ARGEND;
27557dd7cddfSDavid du Colombier 
27567dd7cddfSDavid du Colombier 	switch(argc){
27577dd7cddfSDavid du Colombier 	case 2:
2758ea58ad6fSDavid du Colombier 		if (parseip(remip, argv[1]) == -1)
2759ea58ad6fSDavid du Colombier 			sysfatal("bad remote ip %s", argv[1]);
27607dd7cddfSDavid du Colombier 	case 1:
2761ea58ad6fSDavid du Colombier 		if (parseip(ipaddr, argv[0]) == -1)
2762ea58ad6fSDavid du Colombier 			sysfatal("bad ip %s", argv[0]);
27637dd7cddfSDavid du Colombier 	case 0:
27647dd7cddfSDavid du Colombier 		break;
27657dd7cddfSDavid du Colombier 	default:
27667dd7cddfSDavid du Colombier 		usage();
27677dd7cddfSDavid du Colombier 	}
27687dd7cddfSDavid du Colombier 
27697dd7cddfSDavid du Colombier 	nip = nipifcs(net);
277059cc4ca5SDavid du Colombier 	if(nip == 0 && !server)
277159cc4ca5SDavid du Colombier 		primary = 1;
27727dd7cddfSDavid du Colombier 
27737dd7cddfSDavid du Colombier 	if(dev != nil){
2774d9306527SDavid du Colombier 		mediain = open(dev, ORDWR);
2775d9306527SDavid du Colombier 		if(mediain < 0){
277659cc4ca5SDavid du Colombier 			if(strchr(dev, '!')){
2777d9306527SDavid du Colombier 				if((mediain = dial(dev, 0, 0, &cfd)) == -1){
277859cc4ca5SDavid du Colombier 					fprint(2, "ppp: couldn't dial %s: %r\n", dev);
277959cc4ca5SDavid du Colombier 					exits(dev);
278059cc4ca5SDavid du Colombier 				}
278159cc4ca5SDavid du Colombier 			} else {
27827dd7cddfSDavid du Colombier 				fprint(2, "ppp: couldn't open %s\n", dev);
27837dd7cddfSDavid du Colombier 				exits(dev);
27847dd7cddfSDavid du Colombier 			}
278559cc4ca5SDavid du Colombier 		} else {
27867dd7cddfSDavid du Colombier 			snprint(buf, sizeof buf, "%sctl", dev);
27877dd7cddfSDavid du Colombier 			cfd = open(buf, ORDWR);
278859cc4ca5SDavid du Colombier 		}
27897dd7cddfSDavid du Colombier 		if(cfd > 0){
27907dd7cddfSDavid du Colombier 			if(baud)
27917dd7cddfSDavid du Colombier 				fprint(cfd, "b%d", baud);
27927dd7cddfSDavid du Colombier 			fprint(cfd, "m1");	/* cts/rts flow control (and fifo's) on */
2793223a736eSDavid du Colombier 			fprint(cfd, "q64000");	/* increase q size to 64k */
27947dd7cddfSDavid du Colombier 			fprint(cfd, "n1");	/* nonblocking writes on */
27957dd7cddfSDavid du Colombier 			fprint(cfd, "r1");	/* rts on */
27967dd7cddfSDavid du Colombier 			fprint(cfd, "d1");	/* dtr on */
279759cc4ca5SDavid du Colombier 			fprint(cfd, "c1");	/* dcdhup on */
279839734e7eSDavid du Colombier 			if(user || chatfile)
2799d9306527SDavid du Colombier 				connect(mediain, cfd);
28007dd7cddfSDavid du Colombier 			close(cfd);
28017dd7cddfSDavid du Colombier 		} else {
280239734e7eSDavid du Colombier 			if(user || chatfile)
2803d9306527SDavid du Colombier 				connect(mediain, -1);
28047dd7cddfSDavid du Colombier 		}
2805d9306527SDavid du Colombier 		mediaout = mediain;
28067dd7cddfSDavid du Colombier 	} else {
2807d9306527SDavid du Colombier 		mediain = open("/fd/0", OREAD);
2808d9306527SDavid du Colombier 		if(mediain < 0){
28097dd7cddfSDavid du Colombier 			fprint(2, "ppp: couldn't open /fd/0\n");
28107dd7cddfSDavid du Colombier 			exits("/fd/0");
28117dd7cddfSDavid du Colombier 		}
2812d9306527SDavid du Colombier 		mediaout = open("/fd/1", OWRITE);
2813d9306527SDavid du Colombier 		if(mediaout < 0){
2814d9306527SDavid du Colombier 			fprint(2, "ppp: couldn't open /fd/0\n");
2815d9306527SDavid du Colombier 			exits("/fd/1");
2816d9306527SDavid du Colombier 		}
28177dd7cddfSDavid du Colombier 	}
28187dd7cddfSDavid du Colombier 
2819d9306527SDavid du Colombier 	if(modemcmd != nil && mediaout >= 0)
2820d9306527SDavid du Colombier 		fprint(mediaout, "%s\r", modemcmd);
28217dd7cddfSDavid du Colombier 
28227dd7cddfSDavid du Colombier 	ppp = mallocz(sizeof(*ppp), 1);
2823bedadc12SDavid du Colombier 	pppopen(ppp, mediain, mediaout, net, ipaddr, remip, mtu, framing);
28247dd7cddfSDavid du Colombier 
28257dd7cddfSDavid du Colombier 	/* wait until ip is configured */
282674f16c81SDavid du Colombier 	rendezvous((void*)Rmagic, 0);
28277dd7cddfSDavid du Colombier 
2828dc5a79c1SDavid du Colombier 	if(primary){
28297dd7cddfSDavid du Colombier 		/* create a /net/ndb entry */
28307dd7cddfSDavid du Colombier 		putndb(ppp, net);
28317dd7cddfSDavid du Colombier 	}
28327dd7cddfSDavid du Colombier 
28337dd7cddfSDavid du Colombier 	exits(0);
28347dd7cddfSDavid du Colombier }
28357dd7cddfSDavid du Colombier 
28367dd7cddfSDavid du Colombier void
netlog(char * fmt,...)28377dd7cddfSDavid du Colombier netlog(char *fmt, ...)
28387dd7cddfSDavid du Colombier {
28397dd7cddfSDavid du Colombier 	va_list arg;
28403ff48bf5SDavid du Colombier 	char *m;
28413ff48bf5SDavid du Colombier 	static long start;
28423ff48bf5SDavid du Colombier 	long now;
28433ff48bf5SDavid du Colombier 
28446b6b9ac8SDavid du Colombier 	if(debug == 0)
28456b6b9ac8SDavid du Colombier 		return;
28466b6b9ac8SDavid du Colombier 
28473ff48bf5SDavid du Colombier 	now = time(0);
28483ff48bf5SDavid du Colombier 	if(start == 0)
28493ff48bf5SDavid du Colombier 		start = now;
28507dd7cddfSDavid du Colombier 
28517dd7cddfSDavid du Colombier 	va_start(arg, fmt);
28523ff48bf5SDavid du Colombier 	m = vsmprint(fmt, arg);
28533ff48bf5SDavid du Colombier 	fprint(2, "%ld %s", now-start, m);
28543ff48bf5SDavid du Colombier 	free(m);
28557dd7cddfSDavid du Colombier 	va_end(arg);
28567dd7cddfSDavid du Colombier }
28577dd7cddfSDavid du Colombier 
28587dd7cddfSDavid du Colombier /*
28597dd7cddfSDavid du Colombier  *  return non-zero if this is a valid v4 address
28607dd7cddfSDavid du Colombier  */
28617dd7cddfSDavid du Colombier static int
validv4(Ipaddr addr)28627dd7cddfSDavid du Colombier validv4(Ipaddr addr)
28637dd7cddfSDavid du Colombier {
28647dd7cddfSDavid du Colombier 	return memcmp(addr, v4prefix, IPv4off) == 0 && memcmp(addr, v4prefix, IPaddrlen) != 0;
28657dd7cddfSDavid du Colombier }
28667dd7cddfSDavid du Colombier 
28677dd7cddfSDavid du Colombier static void
invalidate(Ipaddr addr)28687dd7cddfSDavid du Colombier invalidate(Ipaddr addr)
28697dd7cddfSDavid du Colombier {
28707dd7cddfSDavid du Colombier 	ipmove(addr, IPnoaddr);
28717dd7cddfSDavid du Colombier }
28727dd7cddfSDavid du Colombier 
28737dd7cddfSDavid du Colombier /*
28747dd7cddfSDavid du Colombier  *  return number of networks
28757dd7cddfSDavid du Colombier  */
28767dd7cddfSDavid du Colombier static int
nipifcs(char * net)28777dd7cddfSDavid du Colombier nipifcs(char *net)
28787dd7cddfSDavid du Colombier {
28799a747e4fSDavid du Colombier 	static Ipifc *ifc;
28809a747e4fSDavid du Colombier 	Ipifc *nifc;
28819a747e4fSDavid du Colombier 	Iplifc *lifc;
28827dd7cddfSDavid du Colombier 	int n;
28837dd7cddfSDavid du Colombier 
28847dd7cddfSDavid du Colombier 	n = 0;
28859a747e4fSDavid du Colombier 	ifc = readipifc(net, ifc, -1);
28869a747e4fSDavid du Colombier 	for(nifc = ifc; nifc != nil; nifc = nifc->next)
28879a747e4fSDavid du Colombier 		for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next)
28887dd7cddfSDavid du Colombier 			n++;
28897dd7cddfSDavid du Colombier 	return n;
28907dd7cddfSDavid du Colombier }
28917dd7cddfSDavid du Colombier 
28927dd7cddfSDavid du Colombier /*
28937dd7cddfSDavid du Colombier  *   make an ndb entry and put it into /net/ndb for the servers to see
28947dd7cddfSDavid du Colombier  */
28957dd7cddfSDavid du Colombier static void
putndb(PPP * ppp,char * net)28967dd7cddfSDavid du Colombier putndb(PPP *ppp, char *net)
28977dd7cddfSDavid du Colombier {
28987dd7cddfSDavid du Colombier 	char buf[1024];
28997dd7cddfSDavid du Colombier 	char file[64];
29007dd7cddfSDavid du Colombier 	char *p, *e;
29017dd7cddfSDavid du Colombier 	int fd;
29027dd7cddfSDavid du Colombier 
29037dd7cddfSDavid du Colombier 	e = buf + sizeof(buf);
29047dd7cddfSDavid du Colombier 	p = buf;
29057dd7cddfSDavid du Colombier 	p = seprint(p, e, "ip=%I ipmask=255.255.255.255 ipgw=%I\n", ppp->local,
29067dd7cddfSDavid du Colombier 			ppp->remote);
29077dd7cddfSDavid du Colombier 	if(validv4(ppp->dns[0]))
2908312a1df1SDavid du Colombier 		p = seprint(p, e, "\tdns=%I\n", ppp->dns[0]);
29097dd7cddfSDavid du Colombier 	if(validv4(ppp->dns[1]))
2910312a1df1SDavid du Colombier 		p = seprint(p, e, "\tdns=%I\n", ppp->dns[1]);
29117dd7cddfSDavid du Colombier 	if(validv4(ppp->wins[0]))
2912312a1df1SDavid du Colombier 		p = seprint(p, e, "\twins=%I\n", ppp->wins[0]);
29137dd7cddfSDavid du Colombier 	if(validv4(ppp->wins[1]))
2914312a1df1SDavid du Colombier 		p = seprint(p, e, "\twins=%I\n", ppp->wins[1]);
291590630c3aSDavid du Colombier 	seprint(file, file+sizeof file, "%s/ndb", net);
29167dd7cddfSDavid du Colombier 	fd = open(file, OWRITE);
29177dd7cddfSDavid du Colombier 	if(fd < 0)
29187dd7cddfSDavid du Colombier 		return;
29197dd7cddfSDavid du Colombier 	write(fd, buf, p-buf);
29207dd7cddfSDavid du Colombier 	close(fd);
292190630c3aSDavid du Colombier 	seprint(file, file+sizeof file, "%s/cs", net);
292290630c3aSDavid du Colombier 	fd = open(file, OWRITE);
292390630c3aSDavid du Colombier 	write(fd, "refresh", 7);
292490630c3aSDavid du Colombier 	close(fd);
292590630c3aSDavid du Colombier 	seprint(file, file+sizeof file, "%s/dns", net);
292690630c3aSDavid du Colombier 	fd = open(file, OWRITE);
292790630c3aSDavid du Colombier 	write(fd, "refresh", 7);
292890630c3aSDavid du Colombier 	close(fd);
29297dd7cddfSDavid du Colombier }
2930dc5a79c1SDavid du Colombier 
2931dc5a79c1SDavid du Colombier static void
getauth(PPP * ppp)2932dc5a79c1SDavid du Colombier getauth(PPP *ppp)
2933dc5a79c1SDavid du Colombier {
2934dc5a79c1SDavid du Colombier 	UserPasswd *up;
2935dc5a79c1SDavid du Colombier 
2936dc5a79c1SDavid du Colombier 	if(*ppp->chapname)
2937dc5a79c1SDavid du Colombier 		return;
2938dc5a79c1SDavid du Colombier 
2939dc5a79c1SDavid du Colombier 	up = auth_getuserpasswd(auth_getkey,"proto=pass service=ppp %s", keyspec);
2940dc5a79c1SDavid du Colombier 	if(up != nil){
2941dc5a79c1SDavid du Colombier 		strcpy(ppp->chapname, up->user);
2942dc5a79c1SDavid du Colombier 		strcpy(ppp->secret, up->passwd);
2943dc5a79c1SDavid du Colombier 	}
2944dc5a79c1SDavid du Colombier }
2945