xref: /plan9/sys/src/cmd/ip/ppp/mppc.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
17dd7cddfSDavid du Colombier #include <u.h>
27dd7cddfSDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <libsec.h>
47dd7cddfSDavid du Colombier #include <ip.h>
5*9a747e4fSDavid du Colombier #include <auth.h>
67dd7cddfSDavid du Colombier #include "ppp.h"
77dd7cddfSDavid du Colombier 
87dd7cddfSDavid du Colombier enum {
97dd7cddfSDavid du Colombier 	HistorySize=	8*1024,
107dd7cddfSDavid du Colombier 	Cminmatch	= 3,		/* sintest match possible */
117dd7cddfSDavid du Colombier 	Chshift		= 4,		/* nice compromise between space & time */
127dd7cddfSDavid du Colombier 	Cnhash		= 1<<(Chshift*Cminmatch),
137dd7cddfSDavid du Colombier 	HMASK		= Cnhash-1,
147dd7cddfSDavid du Colombier };
157dd7cddfSDavid du Colombier 
167dd7cddfSDavid du Colombier typedef struct Carena Carena;
177dd7cddfSDavid du Colombier struct Carena
187dd7cddfSDavid du Colombier {
197dd7cddfSDavid du Colombier 	uchar	*pos;			/* current place, also amount of history filled */
207dd7cddfSDavid du Colombier 	uchar	buf[HistorySize];
217dd7cddfSDavid du Colombier };
227dd7cddfSDavid du Colombier 
237dd7cddfSDavid du Colombier typedef struct Cstate Cstate;
247dd7cddfSDavid du Colombier struct Cstate
257dd7cddfSDavid du Colombier {
267dd7cddfSDavid du Colombier 	QLock;
277dd7cddfSDavid du Colombier 	int	count;
287dd7cddfSDavid du Colombier 	int	reset;		/* compressor has been reset */
297dd7cddfSDavid du Colombier 	int	front;		/* move to begining of history */
307dd7cddfSDavid du Colombier 	ulong	sreg;		/* output shift reg */
317dd7cddfSDavid du Colombier 	int	bits;		/* number of bits in sreg */
327dd7cddfSDavid du Colombier 	Block	*b; 		/* output block */
337dd7cddfSDavid du Colombier 
347dd7cddfSDavid du Colombier 	/*
357dd7cddfSDavid du Colombier 	 * state for hashing compressor
367dd7cddfSDavid du Colombier 	 */
377dd7cddfSDavid du Colombier 	Carena	arenas[2];
387dd7cddfSDavid du Colombier 	Carena	*hist;
397dd7cddfSDavid du Colombier 	Carena	*ohist;
407dd7cddfSDavid du Colombier 	ulong	hash[Cnhash];
417dd7cddfSDavid du Colombier 	int	h;
427dd7cddfSDavid du Colombier 	ulong	me;
437dd7cddfSDavid du Colombier 	ulong	split;
447dd7cddfSDavid du Colombier 
457dd7cddfSDavid du Colombier 	int	encrypt;
467dd7cddfSDavid du Colombier 	uchar	startkey[16];
477dd7cddfSDavid du Colombier 	uchar	key[16];
487dd7cddfSDavid du Colombier 	RC4state rc4key;
497dd7cddfSDavid du Colombier };
507dd7cddfSDavid du Colombier 
517dd7cddfSDavid du Colombier typedef struct Uncstate Uncstate;
527dd7cddfSDavid du Colombier struct Uncstate
537dd7cddfSDavid du Colombier {
547dd7cddfSDavid du Colombier 	int	count;	 	/* packet count - detects missing packets */
557dd7cddfSDavid du Colombier 	int	resetid;	/* id of reset requests */
567dd7cddfSDavid du Colombier 	uchar	his[HistorySize];
577dd7cddfSDavid du Colombier 	int	indx;		/* current indx in history */
587dd7cddfSDavid du Colombier 	int	size;		/* current history size */
597dd7cddfSDavid du Colombier 	uchar	startkey[16];
607dd7cddfSDavid du Colombier 	uchar	key[16];
617dd7cddfSDavid du Colombier 	RC4state rc4key;
627dd7cddfSDavid du Colombier };
637dd7cddfSDavid du Colombier 
647dd7cddfSDavid du Colombier /* packet flags */
657dd7cddfSDavid du Colombier enum {
667dd7cddfSDavid du Colombier 	Preset=		(1<<15),	/* reset history */
677dd7cddfSDavid du Colombier 	Pfront=		(1<<14),	/* move packet to front of history */
687dd7cddfSDavid du Colombier 	Pcompress=	(1<<13),	/* packet is compressed */
697dd7cddfSDavid du Colombier 	Pencrypt=	(1<<12),	/* packet is encrypted */
707dd7cddfSDavid du Colombier };
717dd7cddfSDavid du Colombier 
727dd7cddfSDavid du Colombier enum {
737dd7cddfSDavid du Colombier 	Lit7,		/* seven bit literal */
747dd7cddfSDavid du Colombier 	Lit8,		/* eight bit literal */
757dd7cddfSDavid du Colombier 	Off6,		/* six bit offset */
767dd7cddfSDavid du Colombier 	Off8,		/* eight bit offset */
777dd7cddfSDavid du Colombier 	Off13,		/* thirteen bit offset */
787dd7cddfSDavid du Colombier };
797dd7cddfSDavid du Colombier 
807dd7cddfSDavid du Colombier /* decode first four bits */
817dd7cddfSDavid du Colombier int decode[16] = {
827dd7cddfSDavid du Colombier 	Lit7,
837dd7cddfSDavid du Colombier 	Lit7,
847dd7cddfSDavid du Colombier 	Lit7,
857dd7cddfSDavid du Colombier 	Lit7,
867dd7cddfSDavid du Colombier 	Lit7,
877dd7cddfSDavid du Colombier 	Lit7,
887dd7cddfSDavid du Colombier 	Lit7,
897dd7cddfSDavid du Colombier 	Lit7,
907dd7cddfSDavid du Colombier 	Lit8,
917dd7cddfSDavid du Colombier 	Lit8,
927dd7cddfSDavid du Colombier 	Lit8,
937dd7cddfSDavid du Colombier 	Lit8,
947dd7cddfSDavid du Colombier 	Off13,
957dd7cddfSDavid du Colombier 	Off13,
967dd7cddfSDavid du Colombier 	Off8,
977dd7cddfSDavid du Colombier 	Off6,
987dd7cddfSDavid du Colombier };
997dd7cddfSDavid du Colombier 
1007dd7cddfSDavid du Colombier 
1017dd7cddfSDavid du Colombier static	void		*compinit(PPP*);
1027dd7cddfSDavid du Colombier static	Block*		comp(PPP*, ushort, Block*, int*);
1037dd7cddfSDavid du Colombier static	void		comp2(Cstate*, uchar*, int);
1047dd7cddfSDavid du Colombier static	Block		*compresetreq(void*, Block*);
1057dd7cddfSDavid du Colombier static	void		compfini(void*);
1067dd7cddfSDavid du Colombier static	void		complit(Cstate*, int);
1077dd7cddfSDavid du Colombier static	void		compcopy(Cstate*, int, int);
1087dd7cddfSDavid du Colombier static	void		compout(Cstate*, ulong, int);
1097dd7cddfSDavid du Colombier static	void		compfront(Cstate*);
1107dd7cddfSDavid du Colombier static	void		hashcheck(Cstate*);
1117dd7cddfSDavid du Colombier static	void		compreset(Cstate*);
1127dd7cddfSDavid du Colombier static	int		hashit(uchar*);
1137dd7cddfSDavid du Colombier 
1147dd7cddfSDavid du Colombier 
1157dd7cddfSDavid du Colombier static	void		*uncinit(PPP*);
1167dd7cddfSDavid du Colombier static	Block*		uncomp(PPP*, Block*, int *protop, Block**);
1177dd7cddfSDavid du Colombier static	Block		*uncomp2(Uncstate *s, Block*, ushort);
1187dd7cddfSDavid du Colombier static	void		uncfini(void*);
1197dd7cddfSDavid du Colombier static	void		uncresetack(void*, Block*);
1207dd7cddfSDavid du Colombier static  int		ipcheck(uchar*, int);
1217dd7cddfSDavid du Colombier static  void		hischeck(Uncstate*);
1227dd7cddfSDavid du Colombier 
1237dd7cddfSDavid du Colombier static	void		setkey(uchar *key, uchar *startkey);
1247dd7cddfSDavid du Colombier 
1257dd7cddfSDavid du Colombier Comptype cmppc = {
1267dd7cddfSDavid du Colombier 	compinit,
1277dd7cddfSDavid du Colombier 	comp,
1287dd7cddfSDavid du Colombier 	compresetreq,
1297dd7cddfSDavid du Colombier 	compfini
1307dd7cddfSDavid du Colombier };
1317dd7cddfSDavid du Colombier 
1327dd7cddfSDavid du Colombier Uncomptype uncmppc = {
1337dd7cddfSDavid du Colombier 	uncinit,
1347dd7cddfSDavid du Colombier 	uncomp,
1357dd7cddfSDavid du Colombier 	uncresetack,
1367dd7cddfSDavid du Colombier 	uncfini
1377dd7cddfSDavid du Colombier };
1387dd7cddfSDavid du Colombier 
1397dd7cddfSDavid du Colombier static void *
compinit(PPP * ppp)1407dd7cddfSDavid du Colombier compinit(PPP *ppp)
1417dd7cddfSDavid du Colombier {
1427dd7cddfSDavid du Colombier 	Cstate *cs;
1437dd7cddfSDavid du Colombier 
1447dd7cddfSDavid du Colombier 	cs = mallocz(sizeof(Cstate), 1);
1457dd7cddfSDavid du Colombier 	cs->hist = &cs->arenas[0];
1467dd7cddfSDavid du Colombier 	cs->ohist = &cs->arenas[1];
1477dd7cddfSDavid du Colombier 	compreset(cs);
1487dd7cddfSDavid du Colombier 	/*
1497dd7cddfSDavid du Colombier 	 * make reset clear the hash table
1507dd7cddfSDavid du Colombier 	 */
1517dd7cddfSDavid du Colombier 	cs->me = ~0;
1527dd7cddfSDavid du Colombier 	compreset(cs);
1537dd7cddfSDavid du Colombier 
1547dd7cddfSDavid du Colombier 	cs->reset = 0;
1557dd7cddfSDavid du Colombier 
1567dd7cddfSDavid du Colombier 	if(ppp->sendencrypted) {
1577dd7cddfSDavid du Colombier 		cs->encrypt = 1;
1587dd7cddfSDavid du Colombier 		memmove(cs->startkey, ppp->key, 16);
1597dd7cddfSDavid du Colombier 		memmove(cs->key, ppp->key, 16);
1607dd7cddfSDavid du Colombier 		setkey(cs->key, cs->startkey);
1617dd7cddfSDavid du Colombier 		setupRC4state(&cs->rc4key, cs->key, 16);
1627dd7cddfSDavid du Colombier 	}
1637dd7cddfSDavid du Colombier 
1647dd7cddfSDavid du Colombier 	return cs;
1657dd7cddfSDavid du Colombier }
1667dd7cddfSDavid du Colombier 
1677dd7cddfSDavid du Colombier static void
compfini(void * as)1687dd7cddfSDavid du Colombier compfini(void *as)
1697dd7cddfSDavid du Colombier {
1707dd7cddfSDavid du Colombier 	Cstate *cs;
1717dd7cddfSDavid du Colombier 
1727dd7cddfSDavid du Colombier 	cs = as;
1737dd7cddfSDavid du Colombier 	free(cs);
1747dd7cddfSDavid du Colombier }
1757dd7cddfSDavid du Colombier 
1767dd7cddfSDavid du Colombier 
1777dd7cddfSDavid du Colombier static Block*
comp(PPP * ppp,ushort proto,Block * b,int * protop)1787dd7cddfSDavid du Colombier comp(PPP *ppp, ushort proto, Block *b, int *protop)
1797dd7cddfSDavid du Colombier {
1807dd7cddfSDavid du Colombier 	Cstate *s;
1817dd7cddfSDavid du Colombier 	int n, n2;
1827dd7cddfSDavid du Colombier 	ushort count;
1837dd7cddfSDavid du Colombier 
1847dd7cddfSDavid du Colombier 	s = ppp->cstate;
1857dd7cddfSDavid du Colombier 	*protop = 0;
1867dd7cddfSDavid du Colombier 
1877dd7cddfSDavid du Colombier 	qlock(s);
1887dd7cddfSDavid du Colombier 
1897dd7cddfSDavid du Colombier 	/* put protocol into b */
1907dd7cddfSDavid du Colombier 	b->rptr -= 2;
1917dd7cddfSDavid du Colombier 	if(b->rptr < b->base)
1927dd7cddfSDavid du Colombier 		sysfatal("mppc: not enough header in block");
1937dd7cddfSDavid du Colombier 	b->rptr[0] = proto>>8;
1947dd7cddfSDavid du Colombier 	b->rptr[1] = proto;
1957dd7cddfSDavid du Colombier 
1967dd7cddfSDavid du Colombier 	n = BLEN(b);
1977dd7cddfSDavid du Colombier 	s->bits = 0;
1987dd7cddfSDavid du Colombier 	s->b = allocb(n*9/8+20);
1997dd7cddfSDavid du Colombier 	s->b->wptr += 2;	/* leave room for mppc header */
2007dd7cddfSDavid du Colombier 
2017dd7cddfSDavid du Colombier 	comp2(s, b->rptr, n);
2027dd7cddfSDavid du Colombier 
2037dd7cddfSDavid du Colombier 	/* flush sreg */
2047dd7cddfSDavid du Colombier 	if(s->bits)
2057dd7cddfSDavid du Colombier 		*s->b->wptr++ = s->sreg<<(8-s->bits);
2067dd7cddfSDavid du Colombier 	if(s->b->wptr > s->b->lim)
2077dd7cddfSDavid du Colombier 		sysfatal("mppc: comp: output block overflowed");
2087dd7cddfSDavid du Colombier 
2097dd7cddfSDavid du Colombier 	n2 = BLEN(s->b);
2107dd7cddfSDavid du Colombier 
2117dd7cddfSDavid du Colombier 	if(n2 > n-2 && !s->encrypt) {
2127dd7cddfSDavid du Colombier 		/* expened and not excrypting so send as a regular packet */
2137dd7cddfSDavid du Colombier //netlog("mppc: comp: expanded\n");
2147dd7cddfSDavid du Colombier 		compreset(s);
2157dd7cddfSDavid du Colombier 		freeb(s->b);
2167dd7cddfSDavid du Colombier 		b->rptr += 2;
2177dd7cddfSDavid du Colombier 		qunlock(s);
2187dd7cddfSDavid du Colombier 		*protop = proto;
2197dd7cddfSDavid du Colombier 		return b;
2207dd7cddfSDavid du Colombier 	}
2217dd7cddfSDavid du Colombier 
2227dd7cddfSDavid du Colombier 	count = s->count++;
2237dd7cddfSDavid du Colombier 	s->count &= 0xfff;
2247dd7cddfSDavid du Colombier 	if(s->front)
2257dd7cddfSDavid du Colombier 		count |= Pfront;
2267dd7cddfSDavid du Colombier 	if(s->reset)
2277dd7cddfSDavid du Colombier 		count |= Preset;
2287dd7cddfSDavid du Colombier 	s->reset = 0;
2297dd7cddfSDavid du Colombier 	s->front = 0;
2307dd7cddfSDavid du Colombier 
2317dd7cddfSDavid du Colombier 	if(n2 > n) {
2327dd7cddfSDavid du Colombier //netlog("mppc: comp: expanded\n");
2337dd7cddfSDavid du Colombier 		freeb(s->b);
2347dd7cddfSDavid du Colombier 		/* make room for count */
2357dd7cddfSDavid du Colombier 		compreset(s);
2367dd7cddfSDavid du Colombier 		b->rptr -= 2;
2377dd7cddfSDavid du Colombier 	} else {
2387dd7cddfSDavid du Colombier 		freeb(b);
2397dd7cddfSDavid du Colombier 		b = s->b;
2407dd7cddfSDavid du Colombier 		count |= Pcompress;
2417dd7cddfSDavid du Colombier 	}
2427dd7cddfSDavid du Colombier 	s->b = nil;
2437dd7cddfSDavid du Colombier 
2447dd7cddfSDavid du Colombier 	if(s->encrypt) {
2457dd7cddfSDavid du Colombier 		count |= Pencrypt;
2467dd7cddfSDavid du Colombier 		if((count&0xff) == 0xff) {
2477dd7cddfSDavid du Colombier //netlog("mppc: comp: changing key\n");
2487dd7cddfSDavid du Colombier 			setkey(s->key, s->startkey);
2497dd7cddfSDavid du Colombier 			setupRC4state(&s->rc4key, s->key, 16);
2507dd7cddfSDavid du Colombier 			rc4(&s->rc4key, s->key, 16);
2517dd7cddfSDavid du Colombier 			setupRC4state(&s->rc4key, s->key, 16);
2527dd7cddfSDavid du Colombier 		} else if(count&Preset)
2537dd7cddfSDavid du Colombier 			setupRC4state(&s->rc4key, s->key, 16);
2547dd7cddfSDavid du Colombier 		rc4(&s->rc4key, b->rptr+2, BLEN(b)-2);
2557dd7cddfSDavid du Colombier //netlog("mppc: encrypt %ux\n", count);
2567dd7cddfSDavid du Colombier 	}
2577dd7cddfSDavid du Colombier 
2587dd7cddfSDavid du Colombier 	b->rptr[0] = count>>8;
2597dd7cddfSDavid du Colombier 	b->rptr[1] = count;
2607dd7cddfSDavid du Colombier 
2617dd7cddfSDavid du Colombier 	qunlock(s);
2627dd7cddfSDavid du Colombier 
2637dd7cddfSDavid du Colombier 	*protop = Pcdata;
2647dd7cddfSDavid du Colombier 	return b;
2657dd7cddfSDavid du Colombier }
2667dd7cddfSDavid du Colombier 
2677dd7cddfSDavid du Colombier static Block *
compresetreq(void * as,Block * b)2687dd7cddfSDavid du Colombier compresetreq(void *as, Block *b)
2697dd7cddfSDavid du Colombier {
2707dd7cddfSDavid du Colombier 	Cstate *cs;
2717dd7cddfSDavid du Colombier 
2727dd7cddfSDavid du Colombier 	cs = as;
2737dd7cddfSDavid du Colombier netlog("mppc: comp: reset request\n");
2747dd7cddfSDavid du Colombier 	qlock(cs);
2757dd7cddfSDavid du Colombier 	compreset(cs);
2767dd7cddfSDavid du Colombier 	qunlock(cs);
2777dd7cddfSDavid du Colombier 
2787dd7cddfSDavid du Colombier 	freeb(b);
2797dd7cddfSDavid du Colombier 
2807dd7cddfSDavid du Colombier 	return nil;
2817dd7cddfSDavid du Colombier }
2827dd7cddfSDavid du Colombier 
2837dd7cddfSDavid du Colombier static void
comp2(Cstate * cs,uchar * p,int n)2847dd7cddfSDavid du Colombier comp2(Cstate *cs, uchar *p, int n)
2857dd7cddfSDavid du Colombier {
2867dd7cddfSDavid du Colombier 	Carena *hist, *ohist;
2877dd7cddfSDavid du Colombier 	ulong *hash, me, split, you, last;
2887dd7cddfSDavid du Colombier 	uchar *s, *t, *et, *buf, *obuf, *pos, *opos;
2897dd7cddfSDavid du Colombier 	int i, h, m;
2907dd7cddfSDavid du Colombier 
2917dd7cddfSDavid du Colombier 	/*
2927dd7cddfSDavid du Colombier 	 * check for wrap
2937dd7cddfSDavid du Colombier 	 */
2947dd7cddfSDavid du Colombier 	if(cs->me + n < cs->me)
2957dd7cddfSDavid du Colombier 		compreset(cs);
2967dd7cddfSDavid du Colombier 
2977dd7cddfSDavid du Colombier 	if(cs->hist->pos + n > cs->hist->buf + HistorySize)
2987dd7cddfSDavid du Colombier 		compfront(cs);
2997dd7cddfSDavid du Colombier 
3007dd7cddfSDavid du Colombier 	hist = cs->hist;
3017dd7cddfSDavid du Colombier 	ohist = cs->ohist;
3027dd7cddfSDavid du Colombier 
3037dd7cddfSDavid du Colombier 	hash = cs->hash;
3047dd7cddfSDavid du Colombier 	me = cs->me;
3057dd7cddfSDavid du Colombier 	split = cs->split;
3067dd7cddfSDavid du Colombier 
3077dd7cddfSDavid du Colombier 	memmove(hist->pos, p, n);
3087dd7cddfSDavid du Colombier 	p = hist->pos;
3097dd7cddfSDavid du Colombier 	hist->pos = pos = p + n;
3107dd7cddfSDavid du Colombier 
3117dd7cddfSDavid du Colombier 	m = Cminmatch;
3127dd7cddfSDavid du Colombier 	if(m > n)
3137dd7cddfSDavid du Colombier 		m = n;
3147dd7cddfSDavid du Colombier 	h = cs->h;
3157dd7cddfSDavid du Colombier 	for(i = 0; i < m; i++) {
3167dd7cddfSDavid du Colombier 		h = (((h)<<Chshift) ^ p[i]) & HMASK;
3177dd7cddfSDavid du Colombier 		last = me + (i - (Cminmatch-1));
3187dd7cddfSDavid du Colombier 		if(last >= split && last != me)
3197dd7cddfSDavid du Colombier 			hash[h] = last;
3207dd7cddfSDavid du Colombier 	}
3217dd7cddfSDavid du Colombier 
3227dd7cddfSDavid du Colombier 	buf = hist->buf - split;
3237dd7cddfSDavid du Colombier 	obuf = ohist->buf + HistorySize - split;
3247dd7cddfSDavid du Colombier 	opos = ohist->pos;
3257dd7cddfSDavid du Colombier 	while(p < pos) {
3267dd7cddfSDavid du Colombier 		you = hash[h];
3277dd7cddfSDavid du Colombier 		if(you < split) {
3287dd7cddfSDavid du Colombier 			if(me - you >= HistorySize)
3297dd7cddfSDavid du Colombier 				t = opos;
3307dd7cddfSDavid du Colombier 			else
3317dd7cddfSDavid du Colombier 				t = obuf + you;
3327dd7cddfSDavid du Colombier 			et = opos;
3337dd7cddfSDavid du Colombier 		} else {
3347dd7cddfSDavid du Colombier 			t = buf + you;
3357dd7cddfSDavid du Colombier 			et = pos;
3367dd7cddfSDavid du Colombier 		}
3377dd7cddfSDavid du Colombier 		m = pos - p;
3387dd7cddfSDavid du Colombier 		if(m < et - t)
3397dd7cddfSDavid du Colombier 			et = t + m;
3407dd7cddfSDavid du Colombier 		for(s = p; t < et; t++) {
3417dd7cddfSDavid du Colombier 			if(*s != *t)
3427dd7cddfSDavid du Colombier 				break;
3437dd7cddfSDavid du Colombier 			s++;
3447dd7cddfSDavid du Colombier 		}
3457dd7cddfSDavid du Colombier 		m = s - p;
3467dd7cddfSDavid du Colombier 		if(m < Cminmatch) {
3477dd7cddfSDavid du Colombier 			complit(cs, *p);
3487dd7cddfSDavid du Colombier 			s = p + 1;
3497dd7cddfSDavid du Colombier 		} else
3507dd7cddfSDavid du Colombier 			compcopy(cs, me - you, m);
3517dd7cddfSDavid du Colombier 
3527dd7cddfSDavid du Colombier 		for(; p != s; p++) {
3537dd7cddfSDavid du Colombier 			if(p + Cminmatch <= pos) {
3547dd7cddfSDavid du Colombier 				hash[h] = me;
3557dd7cddfSDavid du Colombier 				if(p + Cminmatch < pos)
3567dd7cddfSDavid du Colombier 					h = (((h)<<Chshift) ^ p[Cminmatch]) & HMASK;
3577dd7cddfSDavid du Colombier 			}
3587dd7cddfSDavid du Colombier 			me++;
3597dd7cddfSDavid du Colombier 		}
3607dd7cddfSDavid du Colombier 	}
3617dd7cddfSDavid du Colombier 
3627dd7cddfSDavid du Colombier 	cs->h = h;
3637dd7cddfSDavid du Colombier 	cs->me = me;
3647dd7cddfSDavid du Colombier }
3657dd7cddfSDavid du Colombier 
3667dd7cddfSDavid du Colombier static void
compfront(Cstate * cs)3677dd7cddfSDavid du Colombier compfront(Cstate *cs)
3687dd7cddfSDavid du Colombier {
3697dd7cddfSDavid du Colombier 	Carena *th;
3707dd7cddfSDavid du Colombier 
3717dd7cddfSDavid du Colombier 	cs->front = 1;
3727dd7cddfSDavid du Colombier 
3737dd7cddfSDavid du Colombier 	th = cs->ohist;
3747dd7cddfSDavid du Colombier 	cs->ohist = cs->hist;
3757dd7cddfSDavid du Colombier 	cs->hist = th;
3767dd7cddfSDavid du Colombier 	cs->hist->pos = cs->hist->buf;
3777dd7cddfSDavid du Colombier 	cs->h = 0;
3787dd7cddfSDavid du Colombier 	cs->me = cs->split + HistorySize;
3797dd7cddfSDavid du Colombier 	cs->split = cs->me;
3807dd7cddfSDavid du Colombier }
3817dd7cddfSDavid du Colombier 
3827dd7cddfSDavid du Colombier static void
compreset(Cstate * cs)3837dd7cddfSDavid du Colombier compreset(Cstate *cs)
3847dd7cddfSDavid du Colombier {
3857dd7cddfSDavid du Colombier 	ulong me;
3867dd7cddfSDavid du Colombier 
3877dd7cddfSDavid du Colombier 	cs->reset = 1;
3887dd7cddfSDavid du Colombier 
3897dd7cddfSDavid du Colombier 	me = cs->me;
3907dd7cddfSDavid du Colombier 	if(me + 2 * HistorySize < me){
3917dd7cddfSDavid du Colombier 		me = 0;
3927dd7cddfSDavid du Colombier 		memset(cs->hash, 0, sizeof(cs->hash));
3937dd7cddfSDavid du Colombier 	}
3947dd7cddfSDavid du Colombier 	cs->me = me + 2 * HistorySize;
3957dd7cddfSDavid du Colombier 	cs->split = cs->me;
3967dd7cddfSDavid du Colombier 	cs->hist->pos = cs->hist->buf;
3977dd7cddfSDavid du Colombier 	cs->ohist->pos = cs->ohist->buf;
3987dd7cddfSDavid du Colombier }
3997dd7cddfSDavid du Colombier 
4007dd7cddfSDavid du Colombier static void
complit(Cstate * s,int c)4017dd7cddfSDavid du Colombier complit(Cstate *s, int c)
4027dd7cddfSDavid du Colombier {
4037dd7cddfSDavid du Colombier 	if(c&0x80)
4047dd7cddfSDavid du Colombier 		compout(s, 0x100|(c&0x7f), 9);
4057dd7cddfSDavid du Colombier 	else
4067dd7cddfSDavid du Colombier 		compout(s, c, 8);
4077dd7cddfSDavid du Colombier }
4087dd7cddfSDavid du Colombier 
4097dd7cddfSDavid du Colombier static void
compcopy(Cstate * s,int off,int len)4107dd7cddfSDavid du Colombier compcopy(Cstate *s, int off, int len)
4117dd7cddfSDavid du Colombier {
4127dd7cddfSDavid du Colombier 	int i;
4137dd7cddfSDavid du Colombier 	ulong mask;
4147dd7cddfSDavid du Colombier 
4157dd7cddfSDavid du Colombier 	if(off<64)
4167dd7cddfSDavid du Colombier 		compout(s, 0x3c0|off, 10);
4177dd7cddfSDavid du Colombier 	else if(off<320)
4187dd7cddfSDavid du Colombier 		compout(s, 0xe00|(off-64), 12);
4197dd7cddfSDavid du Colombier 	else
4207dd7cddfSDavid du Colombier 		compout(s, 0xc000|(off-320), 16);
4217dd7cddfSDavid du Colombier 	if(len < 3)
4227dd7cddfSDavid du Colombier 		sysfatal("compcopy: bad len: %d", len);
4237dd7cddfSDavid du Colombier 	if(len == 3)
4247dd7cddfSDavid du Colombier 		compout(s, 0, 1);
4257dd7cddfSDavid du Colombier 	else {
4267dd7cddfSDavid du Colombier 		for(i=3; (1<<i) <= len; i++)
4277dd7cddfSDavid du Colombier 			;
4287dd7cddfSDavid du Colombier 		mask = (1<<(i-1))-1;
4297dd7cddfSDavid du Colombier 		compout(s, (((1<<(i-2))-1)<<i) | len&mask, (i-1)<<1);
4307dd7cddfSDavid du Colombier 	}
4317dd7cddfSDavid du Colombier }
4327dd7cddfSDavid du Colombier 
4337dd7cddfSDavid du Colombier static void
compout(Cstate * s,ulong data,int bits)4347dd7cddfSDavid du Colombier compout(Cstate *s, ulong data, int bits)
4357dd7cddfSDavid du Colombier {
4367dd7cddfSDavid du Colombier 	ulong sreg;
4377dd7cddfSDavid du Colombier 
4387dd7cddfSDavid du Colombier 	sreg = s->sreg;
4397dd7cddfSDavid du Colombier 	sreg <<= bits;
4407dd7cddfSDavid du Colombier 	sreg |= data;
4417dd7cddfSDavid du Colombier 	bits += s->bits;
4427dd7cddfSDavid du Colombier 	while(bits >= 8) {
4437dd7cddfSDavid du Colombier 		*s->b->wptr++ = sreg>>(bits-8);
4447dd7cddfSDavid du Colombier 		bits -= 8;
4457dd7cddfSDavid du Colombier 	}
4467dd7cddfSDavid du Colombier 	s->sreg = sreg;
4477dd7cddfSDavid du Colombier 	s->bits = bits;
4487dd7cddfSDavid du Colombier }
4497dd7cddfSDavid du Colombier 
4507dd7cddfSDavid du Colombier void
printkey(uchar * key)4517dd7cddfSDavid du Colombier printkey(uchar *key)
4527dd7cddfSDavid du Colombier {
4537dd7cddfSDavid du Colombier 	char buf[200], *p;
4547dd7cddfSDavid du Colombier 	int i;
4557dd7cddfSDavid du Colombier 
4567dd7cddfSDavid du Colombier 	p = buf;
4577dd7cddfSDavid du Colombier 	for(i=0; i<16; i++)
4587dd7cddfSDavid du Colombier 		p += sprint(p, "%.2ux ", key[i]);
4597dd7cddfSDavid du Colombier //netlog("key = %s\n", buf);
4607dd7cddfSDavid du Colombier }
4617dd7cddfSDavid du Colombier 
4627dd7cddfSDavid du Colombier static	void *
uncinit(PPP * ppp)4637dd7cddfSDavid du Colombier uncinit(PPP *ppp)
4647dd7cddfSDavid du Colombier {
4657dd7cddfSDavid du Colombier 	Uncstate *s;
4667dd7cddfSDavid du Colombier 
4677dd7cddfSDavid du Colombier 	s = mallocz(sizeof(Uncstate), 1);
4687dd7cddfSDavid du Colombier 
4697dd7cddfSDavid du Colombier 	s->count = 0xfff;	/* count of non existant last packet */
4707dd7cddfSDavid du Colombier 	memmove(s->startkey, ppp->key, 16);
4717dd7cddfSDavid du Colombier 	memmove(s->key, ppp->key, 16);
4727dd7cddfSDavid du Colombier 	setkey(s->key, s->startkey);
4737dd7cddfSDavid du Colombier 	setupRC4state(&s->rc4key, s->key, 16);
4747dd7cddfSDavid du Colombier 
4757dd7cddfSDavid du Colombier 	return s;
4767dd7cddfSDavid du Colombier }
4777dd7cddfSDavid du Colombier 
4787dd7cddfSDavid du Colombier static	Block*
uncomp(PPP * ppp,Block * b,int * protop,Block ** r)4797dd7cddfSDavid du Colombier uncomp(PPP *ppp, Block *b, int *protop, Block **r)
4807dd7cddfSDavid du Colombier {
4817dd7cddfSDavid du Colombier 	Uncstate *s;
4827dd7cddfSDavid du Colombier 	ushort proto;
4837dd7cddfSDavid du Colombier 	ushort count;
4847dd7cddfSDavid du Colombier 	Lcpmsg *m;
4857dd7cddfSDavid du Colombier 
4867dd7cddfSDavid du Colombier 	*r = nil;
4877dd7cddfSDavid du Colombier 	*protop = 0;
4887dd7cddfSDavid du Colombier 	s = ppp->uncstate;
4897dd7cddfSDavid du Colombier 	if(BLEN(b) < 2){
4907dd7cddfSDavid du Colombier 		syslog(0, "ppp", ": mppc: short packet\n");
4917dd7cddfSDavid du Colombier 		freeb(b);
4927dd7cddfSDavid du Colombier 		return nil;
4937dd7cddfSDavid du Colombier 	}
4947dd7cddfSDavid du Colombier 	count = nhgets(b->rptr);
4957dd7cddfSDavid du Colombier 	b->rptr += 2;
4967dd7cddfSDavid du Colombier 
4977dd7cddfSDavid du Colombier 	b = uncomp2(s, b, count);
4987dd7cddfSDavid du Colombier 
4997dd7cddfSDavid du Colombier 	if(b == nil) {
5007dd7cddfSDavid du Colombier //netlog("ppp: mppc: reset request\n");
5017dd7cddfSDavid du Colombier 		/* return reset request packet */
5027dd7cddfSDavid du Colombier 		*r = alloclcp(Lresetreq, s->resetid++, 4, &m);
5037dd7cddfSDavid du Colombier 		hnputs(m->len, 4);
5047dd7cddfSDavid du Colombier 		*protop = 0;
5057dd7cddfSDavid du Colombier 		return nil;
5067dd7cddfSDavid du Colombier 	}
5077dd7cddfSDavid du Colombier 
5087dd7cddfSDavid du Colombier 	if(BLEN(b) < 2){
5097dd7cddfSDavid du Colombier 		syslog(0, "ppp", ": mppc: short packet\n");
5107dd7cddfSDavid du Colombier 		freeb(b);
5117dd7cddfSDavid du Colombier 		*protop = 0;
5127dd7cddfSDavid du Colombier 		return nil;
5137dd7cddfSDavid du Colombier 	}
5147dd7cddfSDavid du Colombier 	proto = nhgets(b->rptr);
5157dd7cddfSDavid du Colombier 	b->rptr += 2;
5167dd7cddfSDavid du Colombier 
5177dd7cddfSDavid du Colombier /*
5187dd7cddfSDavid du Colombier 	if(proto == 0x21)
5197dd7cddfSDavid du Colombier 		if(!ipcheck(b->rptr, BLEN(b)))
5207dd7cddfSDavid du Colombier 			hischeck(s);
5217dd7cddfSDavid du Colombier */
5227dd7cddfSDavid du Colombier 
5237dd7cddfSDavid du Colombier 	*protop = proto;
5247dd7cddfSDavid du Colombier 	return b;
5257dd7cddfSDavid du Colombier }
5267dd7cddfSDavid du Colombier 
5277dd7cddfSDavid du Colombier #define NEXTBYTE	sreg = (sreg<<8) | *p++; n--; bits += 8
5287dd7cddfSDavid du Colombier int	maxoff;
5297dd7cddfSDavid du Colombier 
5307dd7cddfSDavid du Colombier static	Block*
uncomp2(Uncstate * s,Block * b,ushort count)5317dd7cddfSDavid du Colombier uncomp2(Uncstate *s, Block *b, ushort count)
5327dd7cddfSDavid du Colombier {
5337dd7cddfSDavid du Colombier 	int ecount, n, bits, off, len, ones;
5347dd7cddfSDavid du Colombier 	ulong sreg;
5357dd7cddfSDavid du Colombier 	int t;
5367dd7cddfSDavid du Colombier 	uchar *p, c, *hp, *hs, *he, *hq;
5377dd7cddfSDavid du Colombier 
5387dd7cddfSDavid du Colombier 	if(count&Preset) {
5397dd7cddfSDavid du Colombier //netlog("mppc reset\n");
5407dd7cddfSDavid du Colombier 		s->indx = 0;
5417dd7cddfSDavid du Colombier 		s->size = 0;
5427dd7cddfSDavid du Colombier 		setupRC4state(&s->rc4key, s->key, 16);
5437dd7cddfSDavid du Colombier 	} else {
5447dd7cddfSDavid du Colombier 		ecount = (s->count+1)&0xfff;
5457dd7cddfSDavid du Colombier 		if((count&0xfff) != ecount) {
5467dd7cddfSDavid du Colombier netlog("******* bad count - got %ux expected %ux\n", count&0xfff, ecount);
5477dd7cddfSDavid du Colombier 			freeb(b);
5487dd7cddfSDavid du Colombier 			return nil;
5497dd7cddfSDavid du Colombier 		}
5507dd7cddfSDavid du Colombier 		if(count&Pfront) {
5517dd7cddfSDavid du Colombier 			s->indx = 0;
5527dd7cddfSDavid du Colombier /*			netlog("ppp: mppc: frount flag set\n"); */
5537dd7cddfSDavid du Colombier 		}
5547dd7cddfSDavid du Colombier 	}
5557dd7cddfSDavid du Colombier 
5567dd7cddfSDavid du Colombier 	/* update key */
5577dd7cddfSDavid du Colombier 	n = (((count+1)>>8)&0xf) - (((s->count+1)>>8)&0xf);
5587dd7cddfSDavid du Colombier 	if(n < 0)
5597dd7cddfSDavid du Colombier 		n += 16;
5607dd7cddfSDavid du Colombier //netlog("mppc count = %ux oldcount %ux n = %d\n", count, s->count, n);
5617dd7cddfSDavid du Colombier 	if(n < 0 || n > 1) {
5627dd7cddfSDavid du Colombier 		syslog(0, "ppp", ": mppc bad count %ux, %ux", count, s->count);
5637dd7cddfSDavid du Colombier 		freeb(b);
5647dd7cddfSDavid du Colombier 		return nil;
5657dd7cddfSDavid du Colombier 	}
5667dd7cddfSDavid du Colombier 	if(n == 1) {
5677dd7cddfSDavid du Colombier 		setkey(s->key, s->startkey);
5687dd7cddfSDavid du Colombier 		setupRC4state(&s->rc4key, s->key, 16);
5697dd7cddfSDavid du Colombier 		rc4(&s->rc4key, s->key, 16);
5707dd7cddfSDavid du Colombier 		setupRC4state(&s->rc4key, s->key, 16);
5717dd7cddfSDavid du Colombier 	}
5727dd7cddfSDavid du Colombier 
5737dd7cddfSDavid du Colombier 	s->count = count;
5747dd7cddfSDavid du Colombier 
5757dd7cddfSDavid du Colombier 	n = BLEN(b);
5767dd7cddfSDavid du Colombier 	p = b->rptr;
5777dd7cddfSDavid du Colombier 	if(count & Pencrypt) {
5787dd7cddfSDavid du Colombier //netlog("mppc unencrypt count = %ux\n", count);
5797dd7cddfSDavid du Colombier 		rc4(&s->rc4key, p, n);
5807dd7cddfSDavid du Colombier 	}
5817dd7cddfSDavid du Colombier 
5827dd7cddfSDavid du Colombier 	if(!(count & Pcompress)) {
5837dd7cddfSDavid du Colombier //netlog("uncompress blen = %d\n", BLEN(b));
5847dd7cddfSDavid du Colombier 		return  b;
5857dd7cddfSDavid du Colombier 	}
5867dd7cddfSDavid du Colombier 
5877dd7cddfSDavid du Colombier 	bits = 0;
5887dd7cddfSDavid du Colombier 	sreg = 0;
5897dd7cddfSDavid du Colombier 	hs = s->his;		/* history start */
5907dd7cddfSDavid du Colombier 	hp = hs+s->indx;	/* write pointer in history */
5917dd7cddfSDavid du Colombier 	he = hs+sizeof(s->his);	/* hsitory end */
5927dd7cddfSDavid du Colombier 	for(;;) {
5937dd7cddfSDavid du Colombier 		if(bits<4) {
5947dd7cddfSDavid du Colombier 			if(n==0) goto Done;
5957dd7cddfSDavid du Colombier 			NEXTBYTE;
5967dd7cddfSDavid du Colombier 		}
5977dd7cddfSDavid du Colombier 		t = decode[(sreg>>(bits-4))&0xf];
5987dd7cddfSDavid du Colombier 		switch(t) {
5997dd7cddfSDavid du Colombier 		default:
6007dd7cddfSDavid du Colombier 			sysfatal("mppc: bad decode!");
6017dd7cddfSDavid du Colombier 		case Lit7:
6027dd7cddfSDavid du Colombier 			bits -= 1;
6037dd7cddfSDavid du Colombier 			if(bits<7) {
6047dd7cddfSDavid du Colombier 				if(n==0) goto Done;
6057dd7cddfSDavid du Colombier 				NEXTBYTE;
6067dd7cddfSDavid du Colombier 			}
6077dd7cddfSDavid du Colombier 			c = (sreg>>(bits-7))&0x7f;
6087dd7cddfSDavid du Colombier 			bits -= 7;
6097dd7cddfSDavid du Colombier 			if(hp >= he) goto His;
6107dd7cddfSDavid du Colombier 			*hp++ = c;
6117dd7cddfSDavid du Colombier /* netlog("\tlit7 %.2ux\n", c); */
6127dd7cddfSDavid du Colombier 			continue;
6137dd7cddfSDavid du Colombier 		case Lit8:
6147dd7cddfSDavid du Colombier 			bits -= 2;
6157dd7cddfSDavid du Colombier 			if(bits<7) {
6167dd7cddfSDavid du Colombier 				if(n==0) goto Eof;
6177dd7cddfSDavid du Colombier 				NEXTBYTE;
6187dd7cddfSDavid du Colombier 			}
6197dd7cddfSDavid du Colombier 			c = 0x80 | ((sreg>>(bits-7))&0x7f);
6207dd7cddfSDavid du Colombier 			bits -= 7;
6217dd7cddfSDavid du Colombier 			if(hp >= he) goto His;
6227dd7cddfSDavid du Colombier 			*hp++ = c;
6237dd7cddfSDavid du Colombier /* netlog("\tlit8 %.2ux\n", c); */
6247dd7cddfSDavid du Colombier 			continue;
6257dd7cddfSDavid du Colombier 		case Off6:
6267dd7cddfSDavid du Colombier 			bits -= 4;
6277dd7cddfSDavid du Colombier 			if(bits<6) {
6287dd7cddfSDavid du Colombier 				if(n==0) goto Eof;
6297dd7cddfSDavid du Colombier 				NEXTBYTE;
6307dd7cddfSDavid du Colombier 			}
6317dd7cddfSDavid du Colombier 			off = (sreg>>(bits-6))&0x3f;
6327dd7cddfSDavid du Colombier 			bits -= 6;
6337dd7cddfSDavid du Colombier 			break;
6347dd7cddfSDavid du Colombier 		case Off8:
6357dd7cddfSDavid du Colombier 			bits -= 4;
6367dd7cddfSDavid du Colombier 			if(bits<8) {
6377dd7cddfSDavid du Colombier 				if(n==0) goto Eof;
6387dd7cddfSDavid du Colombier 				NEXTBYTE;
6397dd7cddfSDavid du Colombier 			}
6407dd7cddfSDavid du Colombier 			off = ((sreg>>(bits-8))&0xff)+64;
6417dd7cddfSDavid du Colombier 			bits -= 8;
6427dd7cddfSDavid du Colombier 			break;
6437dd7cddfSDavid du Colombier 		case Off13:
6447dd7cddfSDavid du Colombier 			bits -= 3;
6457dd7cddfSDavid du Colombier 			while(bits<13) {
6467dd7cddfSDavid du Colombier 				if(n==0) goto Eof;
6477dd7cddfSDavid du Colombier 				NEXTBYTE;
6487dd7cddfSDavid du Colombier 			}
6497dd7cddfSDavid du Colombier 			off = ((sreg>>(bits-13))&0x1fff)+320;
6507dd7cddfSDavid du Colombier 			bits -= 13;
6517dd7cddfSDavid du Colombier /* netlog("\toff=%d bits = %d sreg = %ux t = %x\n", off, bits, sreg, t); */
6527dd7cddfSDavid du Colombier 			break;
6537dd7cddfSDavid du Colombier 		}
6547dd7cddfSDavid du Colombier 		for(ones=0;;ones++) {
6557dd7cddfSDavid du Colombier 			if(bits == 0) {
6567dd7cddfSDavid du Colombier 				if(n==0) goto Eof;
6577dd7cddfSDavid du Colombier 				NEXTBYTE;
6587dd7cddfSDavid du Colombier 			}
6597dd7cddfSDavid du Colombier 			bits--;
6607dd7cddfSDavid du Colombier 			if(!(sreg&(1<<bits)))
6617dd7cddfSDavid du Colombier 				break;
6627dd7cddfSDavid du Colombier 		}
6637dd7cddfSDavid du Colombier 		if(ones>11) {
6647dd7cddfSDavid du Colombier netlog("ppp: mppc: bad length %d\n", ones);
6657dd7cddfSDavid du Colombier 			freeb(b);
6667dd7cddfSDavid du Colombier 			return nil;
6677dd7cddfSDavid du Colombier 		}
6687dd7cddfSDavid du Colombier 		if(ones == 0) {
6697dd7cddfSDavid du Colombier 			len = 3;
6707dd7cddfSDavid du Colombier 		} else {
6717dd7cddfSDavid du Colombier 			ones++;
6727dd7cddfSDavid du Colombier 			while(bits<ones) {
6737dd7cddfSDavid du Colombier 				if(n==0) goto Eof;
6747dd7cddfSDavid du Colombier 				NEXTBYTE;
6757dd7cddfSDavid du Colombier 			}
6767dd7cddfSDavid du Colombier 			len = (1<<ones) | ((sreg>>(bits-ones))&((1<<ones)-1));
6777dd7cddfSDavid du Colombier 			bits -= ones;
6787dd7cddfSDavid du Colombier 		}
6797dd7cddfSDavid du Colombier 
6807dd7cddfSDavid du Colombier 		hq = hp-off;
6817dd7cddfSDavid du Colombier 		if(hq < hs) {
6827dd7cddfSDavid du Colombier 			hq += sizeof(s->his);
6837dd7cddfSDavid du Colombier 			if(hq-hs+len > s->size)
6847dd7cddfSDavid du Colombier 				goto His;
6857dd7cddfSDavid du Colombier 		}
6867dd7cddfSDavid du Colombier 		if(hp+len > he) goto His;
6877dd7cddfSDavid du Colombier 		while(len) {
6887dd7cddfSDavid du Colombier 			*hp++ = *hq++;
6897dd7cddfSDavid du Colombier 			len--;
6907dd7cddfSDavid du Colombier 		}
6917dd7cddfSDavid du Colombier 	}
6927dd7cddfSDavid du Colombier Done:
6937dd7cddfSDavid du Colombier 	freeb(b);
6947dd7cddfSDavid du Colombier 
6957dd7cddfSDavid du Colombier 	/* build up return block */
6967dd7cddfSDavid du Colombier 	hq = hs+s->indx;
6977dd7cddfSDavid du Colombier 	len = hp-hq;
6987dd7cddfSDavid du Colombier 	b = allocb(len);
6997dd7cddfSDavid du Colombier 	memmove(b->wptr, hq, len);
7007dd7cddfSDavid du Colombier 	b->wptr += len;
701*9a747e4fSDavid du Colombier netlog("ppp: mppc: len %d bits = %d n=%d\n", len, bits, n);
7027dd7cddfSDavid du Colombier 
7037dd7cddfSDavid du Colombier 	s->indx += len;
7047dd7cddfSDavid du Colombier 	if(s->indx > s->size)
7057dd7cddfSDavid du Colombier 		s->size = s->indx;
7067dd7cddfSDavid du Colombier 
7077dd7cddfSDavid du Colombier 	return b;
7087dd7cddfSDavid du Colombier Eof:
7097dd7cddfSDavid du Colombier netlog("*****unexpected end of data\n");
7107dd7cddfSDavid du Colombier 	freeb(b);
7117dd7cddfSDavid du Colombier 	return nil;
7127dd7cddfSDavid du Colombier His:
7137dd7cddfSDavid du Colombier netlog("*****bad history\n");
7147dd7cddfSDavid du Colombier 	freeb(b);
7157dd7cddfSDavid du Colombier 	return nil;
7167dd7cddfSDavid du Colombier }
7177dd7cddfSDavid du Colombier 
7187dd7cddfSDavid du Colombier static	void
uncresetack(void *,Block *)7197dd7cddfSDavid du Colombier uncresetack(void*, Block*)
7207dd7cddfSDavid du Colombier {
7217dd7cddfSDavid du Colombier }
7227dd7cddfSDavid du Colombier 
7237dd7cddfSDavid du Colombier static	void
uncfini(void * as)7247dd7cddfSDavid du Colombier uncfini(void *as)
7257dd7cddfSDavid du Colombier {
7267dd7cddfSDavid du Colombier 	Uncstate *s;
7277dd7cddfSDavid du Colombier 
7287dd7cddfSDavid du Colombier 	s = as;
7297dd7cddfSDavid du Colombier 	free(s);
7307dd7cddfSDavid du Colombier }
7317dd7cddfSDavid du Colombier 
7327dd7cddfSDavid du Colombier static void
setkey(uchar * key,uchar * startkey)7337dd7cddfSDavid du Colombier setkey(uchar *key, uchar *startkey)
7347dd7cddfSDavid du Colombier {
7357dd7cddfSDavid du Colombier 	uchar pad[40];
7367dd7cddfSDavid du Colombier 	SHAstate *s;
7377dd7cddfSDavid du Colombier 	uchar digest[SHA1dlen];
7387dd7cddfSDavid du Colombier 
7397dd7cddfSDavid du Colombier 	s = sha1(startkey, 16, nil, nil);
7407dd7cddfSDavid du Colombier 	memset(pad, 0, 40);
7417dd7cddfSDavid du Colombier 	sha1(pad, 40, nil, s);
7427dd7cddfSDavid du Colombier 	sha1(key, 16, nil, s);
7437dd7cddfSDavid du Colombier 	memset(pad, 0xf2, 40);
7447dd7cddfSDavid du Colombier 	sha1(pad, 40, digest, s);
7457dd7cddfSDavid du Colombier 	memmove(key, digest, 16);
7467dd7cddfSDavid du Colombier }
7477dd7cddfSDavid du Colombier 
7487dd7cddfSDavid du Colombier 
7497dd7cddfSDavid du Colombier /* code to check if IP packet looks good */
7507dd7cddfSDavid du Colombier 
7517dd7cddfSDavid du Colombier typedef struct Iphdr Iphdr;
7527dd7cddfSDavid du Colombier struct Iphdr
7537dd7cddfSDavid du Colombier {
7547dd7cddfSDavid du Colombier 	uchar	vihl;		/* Version and header length */
7557dd7cddfSDavid du Colombier 	uchar	tos;		/* Type of service */
7567dd7cddfSDavid du Colombier 	uchar	length[2];	/* packet length */
7577dd7cddfSDavid du Colombier 	uchar	id[2];		/* Identification */
7587dd7cddfSDavid du Colombier 	uchar	frag[2];	/* Fragment information */
7597dd7cddfSDavid du Colombier 	uchar	ttl;		/* Time to live */
7607dd7cddfSDavid du Colombier 	uchar	proto;		/* Protocol */
7617dd7cddfSDavid du Colombier 	uchar	cksum[2];	/* Header checksum */
7627dd7cddfSDavid du Colombier 	uchar	src[4];		/* Ip source */
7637dd7cddfSDavid du Colombier 	uchar	dst[4];		/* Ip destination */
7647dd7cddfSDavid du Colombier };
7657dd7cddfSDavid du Colombier 
7667dd7cddfSDavid du Colombier enum
7677dd7cddfSDavid du Colombier {
7687dd7cddfSDavid du Colombier 	QMAX		= 64*1024-1,
7697dd7cddfSDavid du Colombier 	IP_TCPPROTO	= 6,
7707dd7cddfSDavid du Colombier 	TCP_IPLEN	= 8,
7717dd7cddfSDavid du Colombier 	TCP_PHDRSIZE	= 12,
7727dd7cddfSDavid du Colombier 	TCP_HDRSIZE	= 20,
7737dd7cddfSDavid du Colombier 	TCP_PKT		= TCP_IPLEN+TCP_PHDRSIZE,
7747dd7cddfSDavid du Colombier };
7757dd7cddfSDavid du Colombier 
7767dd7cddfSDavid du Colombier enum
7777dd7cddfSDavid du Colombier {
7787dd7cddfSDavid du Colombier 	UDP_PHDRSIZE	= 12,
7797dd7cddfSDavid du Colombier 	UDP_HDRSIZE	= 20,
7807dd7cddfSDavid du Colombier 	UDP_IPHDR	= 8,
7817dd7cddfSDavid du Colombier 	IP_UDPPROTO	= 17,
7827dd7cddfSDavid du Colombier 	UDP_USEAD	= 12,
7837dd7cddfSDavid du Colombier 	UDP_RELSIZE	= 16,
7847dd7cddfSDavid du Colombier 
7857dd7cddfSDavid du Colombier 	Udprxms		= 200,
7867dd7cddfSDavid du Colombier 	Udptickms	= 100,
7877dd7cddfSDavid du Colombier 	Udpmaxxmit	= 10,
7887dd7cddfSDavid du Colombier };
7897dd7cddfSDavid du Colombier 
7907dd7cddfSDavid du Colombier typedef struct UDPhdr UDPhdr;
7917dd7cddfSDavid du Colombier struct UDPhdr
7927dd7cddfSDavid du Colombier {
7937dd7cddfSDavid du Colombier 	/* ip header */
7947dd7cddfSDavid du Colombier 	uchar	vihl;		/* Version and header length */
7957dd7cddfSDavid du Colombier 	uchar	tos;		/* Type of service */
7967dd7cddfSDavid du Colombier 	uchar	length[2];	/* packet length */
7977dd7cddfSDavid du Colombier 	uchar	id[2];		/* Identification */
7987dd7cddfSDavid du Colombier 	uchar	frag[2];	/* Fragment information */
7997dd7cddfSDavid du Colombier 	uchar	Unused;
8007dd7cddfSDavid du Colombier 	uchar	udpproto;	/* Protocol */
8017dd7cddfSDavid du Colombier 	uchar	udpplen[2];	/* Header plus data length */
8027dd7cddfSDavid du Colombier 	uchar	udpsrc[4];	/* Ip source */
8037dd7cddfSDavid du Colombier 	uchar	udpdst[4];	/* Ip destination */
8047dd7cddfSDavid du Colombier 
8057dd7cddfSDavid du Colombier 	/* udp header */
8067dd7cddfSDavid du Colombier 	uchar	udpsport[2];	/* Source port */
8077dd7cddfSDavid du Colombier 	uchar	udpdport[2];	/* Destination port */
8087dd7cddfSDavid du Colombier 	uchar	udplen[2];	/* data length */
8097dd7cddfSDavid du Colombier 	uchar	udpcksum[2];	/* Checksum */
8107dd7cddfSDavid du Colombier };
8117dd7cddfSDavid du Colombier 
8127dd7cddfSDavid du Colombier typedef struct TCPhdr TCPhdr;
8137dd7cddfSDavid du Colombier struct TCPhdr
8147dd7cddfSDavid du Colombier {
8157dd7cddfSDavid du Colombier 	uchar	vihl;		/* Version and header length */
8167dd7cddfSDavid du Colombier 	uchar	tos;		/* Type of service */
8177dd7cddfSDavid du Colombier 	uchar	length[2];	/* packet length */
8187dd7cddfSDavid du Colombier 	uchar	id[2];		/* Identification */
8197dd7cddfSDavid du Colombier 	uchar	frag[2];	/* Fragment information */
8207dd7cddfSDavid du Colombier 	uchar	Unused;
8217dd7cddfSDavid du Colombier 	uchar	proto;
8227dd7cddfSDavid du Colombier 	uchar	tcplen[2];
8237dd7cddfSDavid du Colombier 	uchar	tcpsrc[4];
8247dd7cddfSDavid du Colombier 	uchar	tcpdst[4];
8257dd7cddfSDavid du Colombier 	uchar	tcpsport[2];
8267dd7cddfSDavid du Colombier 	uchar	tcpdport[2];
8277dd7cddfSDavid du Colombier 	uchar	tcpseq[4];
8287dd7cddfSDavid du Colombier 	uchar	tcpack[4];
8297dd7cddfSDavid du Colombier 	uchar	tcpflag[2];
8307dd7cddfSDavid du Colombier 	uchar	tcpwin[2];
8317dd7cddfSDavid du Colombier 	uchar	tcpcksum[2];
8327dd7cddfSDavid du Colombier 	uchar	tcpurg[2];
8337dd7cddfSDavid du Colombier 	/* Options segment */
8347dd7cddfSDavid du Colombier 	uchar	tcpopt[2];
8357dd7cddfSDavid du Colombier 	uchar	tcpmss[2];
8367dd7cddfSDavid du Colombier };
8377dd7cddfSDavid du Colombier 
8387dd7cddfSDavid du Colombier static void
hischeck(Uncstate * s)8397dd7cddfSDavid du Colombier hischeck(Uncstate *s)
8407dd7cddfSDavid du Colombier {
8417dd7cddfSDavid du Colombier 	uchar *p;
8427dd7cddfSDavid du Colombier 	Iphdr *iph;
8437dd7cddfSDavid du Colombier 	int len;
8447dd7cddfSDavid du Colombier 
8457dd7cddfSDavid du Colombier 	p = s->his;
8467dd7cddfSDavid du Colombier 
8477dd7cddfSDavid du Colombier netlog("***** history check\n");
8487dd7cddfSDavid du Colombier 	while(p < s->his+s->size) {
8497dd7cddfSDavid du Colombier 		if(p[0] != 0 || p[1] != 0x21) {
8507dd7cddfSDavid du Colombier netlog("***** unknown protocol\n");
8517dd7cddfSDavid du Colombier 			return;
8527dd7cddfSDavid du Colombier 		}
8537dd7cddfSDavid du Colombier 		p += 2;
85459cc4ca5SDavid du Colombier netlog("off = %ld ", p-s->his);
8557dd7cddfSDavid du Colombier 		iph = (Iphdr*)p;
8567dd7cddfSDavid du Colombier 		len = nhgets(iph->length);
8577dd7cddfSDavid du Colombier 		ipcheck(p, len);
8587dd7cddfSDavid du Colombier 		p += len;
8597dd7cddfSDavid du Colombier 	}
8607dd7cddfSDavid du Colombier }
8617dd7cddfSDavid du Colombier 
8627dd7cddfSDavid du Colombier 
8637dd7cddfSDavid du Colombier static int
ipcheck(uchar * p,int len)8647dd7cddfSDavid du Colombier ipcheck(uchar *p, int len)
8657dd7cddfSDavid du Colombier {
8667dd7cddfSDavid du Colombier 	Iphdr *iph;
8677dd7cddfSDavid du Colombier 	TCPhdr *tcph;
8687dd7cddfSDavid du Colombier 	ushort length;
8697dd7cddfSDavid du Colombier 	UDPhdr *uh;
8707dd7cddfSDavid du Colombier 	Block *bp;
8717dd7cddfSDavid du Colombier 	ushort cksum;
8727dd7cddfSDavid du Colombier 	int good;
8737dd7cddfSDavid du Colombier 
8747dd7cddfSDavid du Colombier 	bp = allocb(len);
8757dd7cddfSDavid du Colombier 	memmove(bp->wptr, p, len);
8767dd7cddfSDavid du Colombier 	bp->wptr += len;
8777dd7cddfSDavid du Colombier 
8787dd7cddfSDavid du Colombier 	good = 1;
8797dd7cddfSDavid du Colombier 
8807dd7cddfSDavid du Colombier 	iph = (Iphdr *)(bp->rptr);
8817dd7cddfSDavid du Colombier /* netlog("ppp: mppc: ipcheck %I %I len %d proto %d\n", iph->src, iph->dst, BLEN(bp), iph->proto); */
8827dd7cddfSDavid du Colombier 
8837dd7cddfSDavid du Colombier 	if(len != nhgets(iph->length)) {
8847dd7cddfSDavid du Colombier 		netlog("***** bad length! %d %d\n", len, nhgets(iph->length));
8857dd7cddfSDavid du Colombier 		good = 0;
8867dd7cddfSDavid du Colombier 	}
8877dd7cddfSDavid du Colombier 
8887dd7cddfSDavid du Colombier 	cksum = ipcsum(&iph->vihl);
8897dd7cddfSDavid du Colombier 	if(cksum) {
8907dd7cddfSDavid du Colombier 		netlog("***** IP proto cksum!!! %I %ux\n", iph->src, cksum);
8917dd7cddfSDavid du Colombier 		good = 0;
8927dd7cddfSDavid du Colombier 	}
8937dd7cddfSDavid du Colombier 
8947dd7cddfSDavid du Colombier 	switch(iph->proto) {
8957dd7cddfSDavid du Colombier 	default:
8967dd7cddfSDavid du Colombier 		break;
8977dd7cddfSDavid du Colombier 	case IP_TCPPROTO:
8987dd7cddfSDavid du Colombier 
8997dd7cddfSDavid du Colombier 		tcph = (TCPhdr*)(bp->rptr);
9007dd7cddfSDavid du Colombier 
9017dd7cddfSDavid du Colombier 		length = nhgets(tcph->length);
9027dd7cddfSDavid du Colombier 
9037dd7cddfSDavid du Colombier 		tcph->Unused = 0;
9047dd7cddfSDavid du Colombier 		hnputs(tcph->tcplen, length-TCP_PKT);
9057dd7cddfSDavid du Colombier 		cksum = ptclcsum(bp, TCP_IPLEN, length-TCP_IPLEN);
9067dd7cddfSDavid du Colombier 		if(cksum) {
9077dd7cddfSDavid du Colombier 			netlog("***** bad tcp proto cksum %ux!!!\n", cksum);
9087dd7cddfSDavid du Colombier 			good = 0;
9097dd7cddfSDavid du Colombier 		}
9107dd7cddfSDavid du Colombier 		break;
9117dd7cddfSDavid du Colombier 	case IP_UDPPROTO:
9127dd7cddfSDavid du Colombier 		uh = (UDPhdr*)(bp->rptr);
9137dd7cddfSDavid du Colombier 
9147dd7cddfSDavid du Colombier 		/* Put back pseudo header for checksum */
9157dd7cddfSDavid du Colombier 		uh->Unused = 0;
9167dd7cddfSDavid du Colombier 		len = nhgets(uh->udplen);
9177dd7cddfSDavid du Colombier 		hnputs(uh->udpplen, len);
9187dd7cddfSDavid du Colombier 
9197dd7cddfSDavid du Colombier 		if(nhgets(uh->udpcksum)) {
9207dd7cddfSDavid du Colombier 			cksum = ptclcsum(bp, UDP_IPHDR, len+UDP_PHDRSIZE);
9217dd7cddfSDavid du Colombier 			if(cksum) {
9227dd7cddfSDavid du Colombier 				netlog("***** udp: proto cksum!!! %I %ux\n", uh->udpsrc, cksum);
9237dd7cddfSDavid du Colombier 				good = 0;
9247dd7cddfSDavid du Colombier 			}
9257dd7cddfSDavid du Colombier 		}
9267dd7cddfSDavid du Colombier 		break;
9277dd7cddfSDavid du Colombier 	}
9287dd7cddfSDavid du Colombier 	freeb(bp);
9297dd7cddfSDavid du Colombier 	return good;
9307dd7cddfSDavid du Colombier }
931