xref: /plan9-contrib/sys/src/cmd/ip/ppp/thw.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
17dd7cddfSDavid du Colombier #include <u.h>
27dd7cddfSDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <ip.h>
4*9a747e4fSDavid du Colombier #include <auth.h>
57dd7cddfSDavid du Colombier #include "ppp.h"
67dd7cddfSDavid du Colombier #include "thwack.h"
77dd7cddfSDavid du Colombier 
87dd7cddfSDavid du Colombier typedef struct Cstate Cstate;
97dd7cddfSDavid du Colombier struct Cstate
107dd7cddfSDavid du Colombier {
117dd7cddfSDavid du Colombier 	ulong		seq;
127dd7cddfSDavid du Colombier 	Thwack		th;
137dd7cddfSDavid du Colombier 	ulong		stats[ThwStats];
147dd7cddfSDavid du Colombier };
157dd7cddfSDavid du Colombier 
167dd7cddfSDavid du Colombier typedef struct Uncstate Uncstate;
177dd7cddfSDavid du Colombier struct Uncstate
187dd7cddfSDavid du Colombier {
197dd7cddfSDavid du Colombier 	QLock		ackl;			/* lock for acks sent back to compressor */
207dd7cddfSDavid du Colombier 	int		doack;			/* send an ack? */
2159cc4ca5SDavid du Colombier 	int		badpacks;		/* bad packets seen in a row */
227dd7cddfSDavid du Colombier 	ulong		ackseq;			/* packets to ack */
237dd7cddfSDavid du Colombier 	int		ackmask;
247dd7cddfSDavid du Colombier 
257dd7cddfSDavid du Colombier 	int		active;			/* 0 => waiting for resetack */
267dd7cddfSDavid du Colombier 	int		resetid;		/* id of most recent reset */
277dd7cddfSDavid du Colombier 	Unthwack	ut;
287dd7cddfSDavid du Colombier };
297dd7cddfSDavid du Colombier 
307dd7cddfSDavid du Colombier enum
317dd7cddfSDavid du Colombier {
3259cc4ca5SDavid du Colombier 	ThwAcked	= 1UL << 23,
3359cc4ca5SDavid du Colombier 	ThwCompMask	= 3UL << 21,
3459cc4ca5SDavid du Colombier 	ThwCompressed	= 0UL << 21,
3559cc4ca5SDavid du Colombier 	ThwUncomp	= 1UL << 21,
3659cc4ca5SDavid du Colombier 	ThwUncompAdd	= 2UL << 21,		/* uncompressed, but add to decompression buffer */
377dd7cddfSDavid du Colombier 	ThwSeqMask	= 0x0fffff,
3859cc4ca5SDavid du Colombier 	ThwSmallPack	= 96,
397dd7cddfSDavid du Colombier };
407dd7cddfSDavid du Colombier 
417dd7cddfSDavid du Colombier static	void		*compinit(PPP*);
427dd7cddfSDavid du Colombier static	Block*		comp(PPP*, ushort, Block*, int*);
437dd7cddfSDavid du Colombier static	Block		*compresetreq(void*, Block*);
447dd7cddfSDavid du Colombier static	void		compcompack(void*, Block*);
457dd7cddfSDavid du Colombier static	void		compfini(void*);
467dd7cddfSDavid du Colombier 
477dd7cddfSDavid du Colombier static	void		*uncinit(PPP*);
487dd7cddfSDavid du Colombier static	Block*		uncomp(PPP*, Block*, int *protop, Block**);
497dd7cddfSDavid du Colombier static	void		uncfini(void*);
507dd7cddfSDavid du Colombier static	void		uncresetack(void*, Block*);
517dd7cddfSDavid du Colombier 
527dd7cddfSDavid du Colombier Comptype cthwack = {
537dd7cddfSDavid du Colombier 	compinit,
547dd7cddfSDavid du Colombier 	comp,
557dd7cddfSDavid du Colombier 	compresetreq,
567dd7cddfSDavid du Colombier 	compfini
577dd7cddfSDavid du Colombier };
587dd7cddfSDavid du Colombier 
597dd7cddfSDavid du Colombier Uncomptype uncthwack = {
607dd7cddfSDavid du Colombier 	uncinit,
617dd7cddfSDavid du Colombier 	uncomp,
627dd7cddfSDavid du Colombier 	uncresetack,
637dd7cddfSDavid du Colombier 	uncfini
647dd7cddfSDavid du Colombier };
657dd7cddfSDavid du Colombier 
667dd7cddfSDavid du Colombier static void *
compinit(PPP *)677dd7cddfSDavid du Colombier compinit(PPP *)
687dd7cddfSDavid du Colombier {
697dd7cddfSDavid du Colombier 	Cstate *cs;
707dd7cddfSDavid du Colombier 
717dd7cddfSDavid du Colombier 	cs = mallocz(sizeof(Cstate), 1);
727dd7cddfSDavid du Colombier 	thwackinit(&cs->th);
737dd7cddfSDavid du Colombier 	return cs;
747dd7cddfSDavid du Colombier }
757dd7cddfSDavid du Colombier 
767dd7cddfSDavid du Colombier static void
compfini(void * as)777dd7cddfSDavid du Colombier compfini(void *as)
787dd7cddfSDavid du Colombier {
797dd7cddfSDavid du Colombier 	Cstate *cs;
807dd7cddfSDavid du Colombier 
817dd7cddfSDavid du Colombier 	cs = as;
827dd7cddfSDavid du Colombier 	thwackcleanup(&cs->th);
837dd7cddfSDavid du Colombier 	free(cs);
847dd7cddfSDavid du Colombier }
857dd7cddfSDavid du Colombier 
8659cc4ca5SDavid du Colombier 
8759cc4ca5SDavid du Colombier static Block *
compresetreq(void * as,Block * b)8859cc4ca5SDavid du Colombier compresetreq(void *as, Block *b)
8959cc4ca5SDavid du Colombier {
9059cc4ca5SDavid du Colombier 	Cstate *cs;
9159cc4ca5SDavid du Colombier 	Lcpmsg *m;
9259cc4ca5SDavid du Colombier 	int id;
9359cc4ca5SDavid du Colombier 
9459cc4ca5SDavid du Colombier 	cs = as;
9559cc4ca5SDavid du Colombier 	m = (Lcpmsg*)b->rptr;
9659cc4ca5SDavid du Colombier 	id = m->id;
9759cc4ca5SDavid du Colombier 
9859cc4ca5SDavid du Colombier 	thwackinit(&cs->th);
9959cc4ca5SDavid du Colombier 
10059cc4ca5SDavid du Colombier 	freeb(b);
10159cc4ca5SDavid du Colombier 
10259cc4ca5SDavid du Colombier 	netlog("thwack resetreq id=%d \n", id);
10359cc4ca5SDavid du Colombier 
10459cc4ca5SDavid du Colombier 	b = alloclcp(Lresetack, id, 4, &m);
10559cc4ca5SDavid du Colombier 	hnputs(m->len, 4);
10659cc4ca5SDavid du Colombier 
10759cc4ca5SDavid du Colombier 	return b;
10859cc4ca5SDavid du Colombier }
10959cc4ca5SDavid du Colombier 
1107dd7cddfSDavid du Colombier static Block*
comp(PPP * ppp,ushort proto,Block * b,int * protop)1117dd7cddfSDavid du Colombier comp(PPP *ppp, ushort proto, Block *b, int *protop)
1127dd7cddfSDavid du Colombier {
1137dd7cddfSDavid du Colombier 	Uncstate *uncs;
1147dd7cddfSDavid du Colombier 	Cstate *cs;
1157dd7cddfSDavid du Colombier 	Block *bb;
1167dd7cddfSDavid du Colombier 	ulong seq, acked;
11759cc4ca5SDavid du Colombier 	int n, nn, mustadd;
1187dd7cddfSDavid du Colombier 
1197dd7cddfSDavid du Colombier 	cs = ppp->cstate;
1207dd7cddfSDavid du Colombier 	*protop = 0;
1217dd7cddfSDavid du Colombier 
1227dd7cddfSDavid du Colombier 	/* put ack and protocol into b */
1237dd7cddfSDavid du Colombier 	n = BLEN(b);
1247dd7cddfSDavid du Colombier 	if(b->rptr - (2+4) < b->base)
1257dd7cddfSDavid du Colombier 		sysfatal("thwack: not enough header in block");
1267dd7cddfSDavid du Colombier 	acked = 0;
1277dd7cddfSDavid du Colombier 	if(ppp->unctype == &uncthwack){
1287dd7cddfSDavid du Colombier 		uncs = ppp->uncstate;
1297dd7cddfSDavid du Colombier 		qlock(&uncs->ackl);
1307dd7cddfSDavid du Colombier 		if(uncs->doack){
1317dd7cddfSDavid du Colombier 			uncs->doack = 0;
1327dd7cddfSDavid du Colombier 			b->rptr -= 4;
1337dd7cddfSDavid du Colombier 			b->rptr[0] = uncs->ackseq >> 16;
1347dd7cddfSDavid du Colombier 			b->rptr[1] = uncs->ackseq >> 8;
1357dd7cddfSDavid du Colombier 			b->rptr[2] = uncs->ackseq;
1367dd7cddfSDavid du Colombier 			b->rptr[3] = uncs->ackmask;
1377dd7cddfSDavid du Colombier 			acked = ThwAcked;
1387dd7cddfSDavid du Colombier 		}
1397dd7cddfSDavid du Colombier 		qunlock(&uncs->ackl);
1407dd7cddfSDavid du Colombier 	}
1417dd7cddfSDavid du Colombier 	if(proto > 0xff){
1427dd7cddfSDavid du Colombier 		b->rptr -= 2;
1437dd7cddfSDavid du Colombier 		b->rptr[0] = proto >> 8;
1447dd7cddfSDavid du Colombier 		b->rptr[1] = proto;
1457dd7cddfSDavid du Colombier 	}else{
1467dd7cddfSDavid du Colombier 		b->rptr--;
1477dd7cddfSDavid du Colombier 		b->rptr[0] = proto;
1487dd7cddfSDavid du Colombier 	}
1497dd7cddfSDavid du Colombier 
1507dd7cddfSDavid du Colombier 	bb = allocb(BLEN(b) + 3);
1517dd7cddfSDavid du Colombier 
1527dd7cddfSDavid du Colombier 	seq = cs->seq;
15359cc4ca5SDavid du Colombier 	if(n <= 3){
15459cc4ca5SDavid du Colombier 		mustadd = 0;
15559cc4ca5SDavid du Colombier 		nn = -1;
15659cc4ca5SDavid du Colombier 	}else{
15759cc4ca5SDavid du Colombier 		mustadd = n < ThwSmallPack;
15859cc4ca5SDavid du Colombier 		nn = thwack(&cs->th, mustadd, bb->wptr + 3, n - 3, b, seq, cs->stats);
15959cc4ca5SDavid du Colombier 	}
16059cc4ca5SDavid du Colombier 	if(nn < 0 && !mustadd){
1617dd7cddfSDavid du Colombier 		if(!acked || BLEN(b) + 1 > ppp->mtu){
1627dd7cddfSDavid du Colombier 			freeb(bb);
1637dd7cddfSDavid du Colombier 			if(acked)
1647dd7cddfSDavid du Colombier 				b->rptr += 4;
1657dd7cddfSDavid du Colombier 			if(proto > 0xff)
1667dd7cddfSDavid du Colombier 				b->rptr += 2;
1677dd7cddfSDavid du Colombier 			else
1687dd7cddfSDavid du Colombier 				b->rptr++;
1697dd7cddfSDavid du Colombier 			*protop = proto;
1707dd7cddfSDavid du Colombier 			return b;
1717dd7cddfSDavid du Colombier 		}
17259cc4ca5SDavid du Colombier 		bb->wptr[0] = (ThwUncomp | ThwAcked) >> 16;
17359cc4ca5SDavid du Colombier 
17459cc4ca5SDavid du Colombier 		memmove(bb->wptr + 1, b->rptr, BLEN(b));
17559cc4ca5SDavid du Colombier 
17659cc4ca5SDavid du Colombier 		bb->wptr += BLEN(b) + 1;
1777dd7cddfSDavid du Colombier 		freeb(b);
1787dd7cddfSDavid du Colombier 	}else{
1797dd7cddfSDavid du Colombier 		cs->seq = (seq + 1) & ThwSeqMask;
18059cc4ca5SDavid du Colombier 		if(nn < 0){
18159cc4ca5SDavid du Colombier 			nn = BLEN(b);
18259cc4ca5SDavid du Colombier 			memmove(bb->wptr + 3, b->rptr, nn);
18359cc4ca5SDavid du Colombier 			seq |= ThwUncompAdd;
18459cc4ca5SDavid du Colombier 		}else
18559cc4ca5SDavid du Colombier 			seq |= ThwCompressed;
18659cc4ca5SDavid du Colombier 		seq |= acked;
18759cc4ca5SDavid du Colombier 		bb->wptr[0] = seq>>16;
18859cc4ca5SDavid du Colombier 		bb->wptr[1] = seq>>8;
18959cc4ca5SDavid du Colombier 		bb->wptr[2] = seq;
1907dd7cddfSDavid du Colombier 
19159cc4ca5SDavid du Colombier 		bb->wptr += nn + 3;
1927dd7cddfSDavid du Colombier 	}
1937dd7cddfSDavid du Colombier 
1947dd7cddfSDavid du Colombier 	*protop = Pcdata;
1957dd7cddfSDavid du Colombier 	return bb;
1967dd7cddfSDavid du Colombier }
1977dd7cddfSDavid du Colombier 
1987dd7cddfSDavid du Colombier static	void *
uncinit(PPP *)1997dd7cddfSDavid du Colombier uncinit(PPP *)
2007dd7cddfSDavid du Colombier {
2017dd7cddfSDavid du Colombier 	Uncstate *s;
2027dd7cddfSDavid du Colombier 
2037dd7cddfSDavid du Colombier 	s = mallocz(sizeof(Uncstate), 1);
2047dd7cddfSDavid du Colombier 
2057dd7cddfSDavid du Colombier 	s->active = 1;
2067dd7cddfSDavid du Colombier 
2077dd7cddfSDavid du Colombier 	unthwackinit(&s->ut);
2087dd7cddfSDavid du Colombier 
2097dd7cddfSDavid du Colombier 	return s;
2107dd7cddfSDavid du Colombier }
2117dd7cddfSDavid du Colombier 
21259cc4ca5SDavid du Colombier static	void
uncfini(void * as)21359cc4ca5SDavid du Colombier uncfini(void *as)
21459cc4ca5SDavid du Colombier {
21559cc4ca5SDavid du Colombier 	free(as);
21659cc4ca5SDavid du Colombier }
21759cc4ca5SDavid du Colombier 
21859cc4ca5SDavid du Colombier static	void
uncresetack(void * as,Block * b)21959cc4ca5SDavid du Colombier uncresetack(void *as, Block *b)
22059cc4ca5SDavid du Colombier {
22159cc4ca5SDavid du Colombier 	Uncstate *s;
22259cc4ca5SDavid du Colombier 	Lcpmsg *m;
22359cc4ca5SDavid du Colombier 
22459cc4ca5SDavid du Colombier 	s = as;
22559cc4ca5SDavid du Colombier 	m = (Lcpmsg*)b->rptr;
22659cc4ca5SDavid du Colombier 
22759cc4ca5SDavid du Colombier 	/*
22859cc4ca5SDavid du Colombier 	 * rfc 1962 says we must reset every message
22959cc4ca5SDavid du Colombier 	 * we don't since we may have acked some messages
23059cc4ca5SDavid du Colombier 	 * which the compressor will use in the future.
23159cc4ca5SDavid du Colombier 	 */
23259cc4ca5SDavid du Colombier 	netlog("unthwack resetack id=%d resetid=%d active=%d\n", m->id, s->resetid, s->active);
23359cc4ca5SDavid du Colombier 	if(m->id == (uchar)s->resetid && !s->active){
23459cc4ca5SDavid du Colombier 		s->active = 1;
23559cc4ca5SDavid du Colombier 		unthwackinit(&s->ut);
23659cc4ca5SDavid du Colombier 	}
23759cc4ca5SDavid du Colombier }
23859cc4ca5SDavid du Colombier 
2397dd7cddfSDavid du Colombier static	Block*
uncomp(PPP * ppp,Block * bb,int * protop,Block ** reply)2407dd7cddfSDavid du Colombier uncomp(PPP *ppp, Block *bb, int *protop, Block **reply)
2417dd7cddfSDavid du Colombier {
24259cc4ca5SDavid du Colombier 	Lcpmsg *m;
2437dd7cddfSDavid du Colombier 	Cstate *cs;
2447dd7cddfSDavid du Colombier 	Uncstate *uncs;
2457dd7cddfSDavid du Colombier 	Block *b, *r;
2467dd7cddfSDavid du Colombier 	ulong seq, mseq;
24759cc4ca5SDavid du Colombier 	ushort proto;
2487dd7cddfSDavid du Colombier 	uchar mask;
2497dd7cddfSDavid du Colombier 	int n;
2507dd7cddfSDavid du Colombier 
2517dd7cddfSDavid du Colombier 	*reply = nil;
2527dd7cddfSDavid du Colombier 	*protop = 0;
2537dd7cddfSDavid du Colombier 	uncs = ppp->uncstate;
2547dd7cddfSDavid du Colombier 
2557dd7cddfSDavid du Colombier 	if(BLEN(bb) < 4){
2567dd7cddfSDavid du Colombier 		syslog(0, "ppp", ": thwack: short packet\n");
2577dd7cddfSDavid du Colombier 		freeb(bb);
2587dd7cddfSDavid du Colombier 		return nil;
2597dd7cddfSDavid du Colombier 	}
2607dd7cddfSDavid du Colombier 
2617dd7cddfSDavid du Colombier 	if(!uncs->active){
2627dd7cddfSDavid du Colombier 		netlog("unthwack: inactive, killing packet\n");
2637dd7cddfSDavid du Colombier 		freeb(bb);
2647dd7cddfSDavid du Colombier 		r = alloclcp(Lresetreq, uncs->resetid, 4, &m);
2657dd7cddfSDavid du Colombier 		hnputs(m->len, 4);
2667dd7cddfSDavid du Colombier 		*reply = r;
2677dd7cddfSDavid du Colombier 		return nil;
2687dd7cddfSDavid du Colombier 	}
2697dd7cddfSDavid du Colombier 
2707dd7cddfSDavid du Colombier 	seq = bb->rptr[0] << 16;
27159cc4ca5SDavid du Colombier 	if((seq & ThwCompMask) == ThwUncomp){
27259cc4ca5SDavid du Colombier 		bb->rptr++;
27359cc4ca5SDavid du Colombier 		b = bb;
27459cc4ca5SDavid du Colombier 	}else{
2757dd7cddfSDavid du Colombier 		seq |= (bb->rptr[1]<<8) | bb->rptr[2];
2767dd7cddfSDavid du Colombier 		bb->rptr += 3;
27759cc4ca5SDavid du Colombier 		if((seq & ThwCompMask) == ThwCompressed){
2787dd7cddfSDavid du Colombier 			b = allocb(ThwMaxBlock);
2797dd7cddfSDavid du Colombier 			n = unthwack(&uncs->ut, b->wptr, ThwMaxBlock, bb->rptr, BLEN(bb), seq & ThwSeqMask);
2807dd7cddfSDavid du Colombier 			freeb(bb);
2817dd7cddfSDavid du Colombier 			if(n < 2){
2827dd7cddfSDavid du Colombier 				syslog(0, "ppp", ": unthwack: short or corrupted packet %d seq=%ld\n", n, seq);
28359cc4ca5SDavid du Colombier 				netlog("unthwack: short or corrupted packet n=%d seq=%ld: %s\n", n, seq, uncs->ut.err);
2847dd7cddfSDavid du Colombier 				freeb(b);
2857dd7cddfSDavid du Colombier 
2867dd7cddfSDavid du Colombier 				r = alloclcp(Lresetreq, ++uncs->resetid, 4, &m);
2877dd7cddfSDavid du Colombier 				hnputs(m->len, 4);
2887dd7cddfSDavid du Colombier 				*reply = r;
2897dd7cddfSDavid du Colombier 				uncs->active = 0;
2907dd7cddfSDavid du Colombier 				return nil;
2917dd7cddfSDavid du Colombier 			}
2927dd7cddfSDavid du Colombier 			b->wptr += n;
29359cc4ca5SDavid du Colombier 		}else{
29459cc4ca5SDavid du Colombier 			unthwackadd(&uncs->ut, bb->rptr, BLEN(bb), seq & ThwSeqMask);
29559cc4ca5SDavid du Colombier 			b = bb;
29659cc4ca5SDavid du Colombier 		}
2977dd7cddfSDavid du Colombier 
2987dd7cddfSDavid du Colombier 		/*
2997dd7cddfSDavid du Colombier 		 * update ack state
3007dd7cddfSDavid du Colombier 		 */
3017dd7cddfSDavid du Colombier 		mseq = unthwackstate(&uncs->ut, &mask);
3027dd7cddfSDavid du Colombier 		qlock(&uncs->ackl);
3037dd7cddfSDavid du Colombier 		uncs->ackseq = mseq;
3047dd7cddfSDavid du Colombier 		uncs->ackmask = mask;
3057dd7cddfSDavid du Colombier 		uncs->doack = 1;
3067dd7cddfSDavid du Colombier 		qunlock(&uncs->ackl);
3077dd7cddfSDavid du Colombier 	}
3087dd7cddfSDavid du Colombier 
3097dd7cddfSDavid du Colombier 	/*
3107dd7cddfSDavid du Colombier 	 * grab the compressed protocol field
3117dd7cddfSDavid du Colombier 	 */
3127dd7cddfSDavid du Colombier 	proto = *b->rptr++;
3137dd7cddfSDavid du Colombier 	if((proto & 1) == 0)
3147dd7cddfSDavid du Colombier 		proto = (proto << 8) | *b->rptr++;
3157dd7cddfSDavid du Colombier 	*protop = proto;
3167dd7cddfSDavid du Colombier 
3177dd7cddfSDavid du Colombier 	/*
3187dd7cddfSDavid du Colombier 	 * decode the ack, and forward to compressor
3197dd7cddfSDavid du Colombier 	 */
3207dd7cddfSDavid du Colombier 	if(seq & ThwAcked){
3217dd7cddfSDavid du Colombier 		if(ppp->ctype == &cthwack){
3227dd7cddfSDavid du Colombier 			cs = ppp->cstate;
3237dd7cddfSDavid du Colombier 			mseq = (b->rptr[0]<<16) | (b->rptr[1]<<8) | b->rptr[2];
3247dd7cddfSDavid du Colombier 			mask = b->rptr[3];
3257dd7cddfSDavid du Colombier 			thwackack(&cs->th, mseq, mask);
3267dd7cddfSDavid du Colombier 		}
3277dd7cddfSDavid du Colombier 		b->rptr += 4;
3287dd7cddfSDavid du Colombier 	}
3297dd7cddfSDavid du Colombier 	return b;
3307dd7cddfSDavid du Colombier }
331