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