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 enum
97dd7cddfSDavid du Colombier {
107dd7cddfSDavid du Colombier DMaxFastLen = 7,
117dd7cddfSDavid du Colombier DBigLenCode = 0x3c, /* minimum code for large lenth encoding */
127dd7cddfSDavid du Colombier DBigLenBits = 6,
137dd7cddfSDavid du Colombier DBigLenBase = 1 /* starting items to encode for big lens */
147dd7cddfSDavid du Colombier };
157dd7cddfSDavid du Colombier
167dd7cddfSDavid du Colombier static uchar lenval[1 << (DBigLenBits - 1)] =
177dd7cddfSDavid du Colombier {
187dd7cddfSDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
197dd7cddfSDavid du Colombier 3, 3, 3, 3, 3, 3, 3, 3,
207dd7cddfSDavid du Colombier 4, 4, 4, 4,
217dd7cddfSDavid du Colombier 5,
227dd7cddfSDavid du Colombier 6,
237dd7cddfSDavid du Colombier 255,
247dd7cddfSDavid du Colombier 255
257dd7cddfSDavid du Colombier };
267dd7cddfSDavid du Colombier
277dd7cddfSDavid du Colombier static uchar lenbits[] =
287dd7cddfSDavid du Colombier {
297dd7cddfSDavid du Colombier 0, 0, 0,
307dd7cddfSDavid du Colombier 2, 3, 5, 5,
317dd7cddfSDavid du Colombier };
327dd7cddfSDavid du Colombier
337dd7cddfSDavid du Colombier static uchar offbits[16] =
347dd7cddfSDavid du Colombier {
357dd7cddfSDavid du Colombier 5, 5, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 12, 13
367dd7cddfSDavid du Colombier };
377dd7cddfSDavid du Colombier
387dd7cddfSDavid du Colombier static ushort offbase[16] =
397dd7cddfSDavid du Colombier {
407dd7cddfSDavid du Colombier 0, 0x20,
417dd7cddfSDavid du Colombier 0x40, 0x60,
427dd7cddfSDavid du Colombier 0x80, 0xc0,
437dd7cddfSDavid du Colombier 0x100, 0x180,
447dd7cddfSDavid du Colombier 0x200, 0x300,
457dd7cddfSDavid du Colombier 0x400, 0x600,
467dd7cddfSDavid du Colombier 0x800, 0xc00,
477dd7cddfSDavid du Colombier 0x1000,
487dd7cddfSDavid du Colombier 0x2000
497dd7cddfSDavid du Colombier };
507dd7cddfSDavid du Colombier
517dd7cddfSDavid du Colombier void
unthwackinit(Unthwack * ut)527dd7cddfSDavid du Colombier unthwackinit(Unthwack *ut)
537dd7cddfSDavid du Colombier {
547dd7cddfSDavid du Colombier int i;
557dd7cddfSDavid du Colombier
567dd7cddfSDavid du Colombier memset(ut, 0, sizeof *ut);
577dd7cddfSDavid du Colombier for(i = 0; i < DWinBlocks; i++)
587dd7cddfSDavid du Colombier ut->blocks[i].data = ut->data[i];
597dd7cddfSDavid du Colombier }
607dd7cddfSDavid du Colombier
617dd7cddfSDavid du Colombier ulong
unthwackstate(Unthwack * ut,uchar * mask)627dd7cddfSDavid du Colombier unthwackstate(Unthwack *ut, uchar *mask)
637dd7cddfSDavid du Colombier {
647dd7cddfSDavid du Colombier ulong bseq, seq;
657dd7cddfSDavid du Colombier int slot, m;
667dd7cddfSDavid du Colombier
67*9a747e4fSDavid du Colombier seq = ~0UL;
687dd7cddfSDavid du Colombier m = 0;
697dd7cddfSDavid du Colombier slot = ut->slot;
707dd7cddfSDavid du Colombier for(;;){
717dd7cddfSDavid du Colombier slot--;
727dd7cddfSDavid du Colombier if(slot < 0)
737dd7cddfSDavid du Colombier slot += DWinBlocks;
747dd7cddfSDavid du Colombier if(slot == ut->slot)
757dd7cddfSDavid du Colombier break;
767dd7cddfSDavid du Colombier if(ut->blocks[slot].maxoff == 0)
77*9a747e4fSDavid du Colombier continue;
787dd7cddfSDavid du Colombier bseq = ut->blocks[slot].seq;
79*9a747e4fSDavid du Colombier if(seq == ~0UL)
807dd7cddfSDavid du Colombier seq = bseq;
817dd7cddfSDavid du Colombier else if(seq - bseq > MaxSeqMask)
827dd7cddfSDavid du Colombier break;
837dd7cddfSDavid du Colombier else
847dd7cddfSDavid du Colombier m |= 1 << (seq - bseq - 1);
857dd7cddfSDavid du Colombier }
867dd7cddfSDavid du Colombier *mask = m;
877dd7cddfSDavid du Colombier return seq;
887dd7cddfSDavid du Colombier }
897dd7cddfSDavid du Colombier
90*9a747e4fSDavid du Colombier /*
91*9a747e4fSDavid du Colombier * insert this block in it's correct sequence number order.
92*9a747e4fSDavid du Colombier * replace the oldest block, which is always pointed to by ut->slot.
93*9a747e4fSDavid du Colombier * the encoder doesn't use a history at wraparound,
94*9a747e4fSDavid du Colombier * so don't worry about that case.
95*9a747e4fSDavid du Colombier */
96*9a747e4fSDavid du Colombier static int
unthwackinsert(Unthwack * ut,int len,ulong seq)97*9a747e4fSDavid du Colombier unthwackinsert(Unthwack *ut, int len, ulong seq)
9859cc4ca5SDavid du Colombier {
9959cc4ca5SDavid du Colombier uchar *d;
10059cc4ca5SDavid du Colombier int slot, tslot;
10159cc4ca5SDavid du Colombier
10259cc4ca5SDavid du Colombier tslot = ut->slot;
10359cc4ca5SDavid du Colombier for(;;){
10459cc4ca5SDavid du Colombier slot = tslot - 1;
10559cc4ca5SDavid du Colombier if(slot < 0)
10659cc4ca5SDavid du Colombier slot += DWinBlocks;
107*9a747e4fSDavid du Colombier if(ut->blocks[slot].seq <= seq || ut->blocks[slot].maxoff == 0)
10859cc4ca5SDavid du Colombier break;
10959cc4ca5SDavid du Colombier d = ut->blocks[tslot].data;
11059cc4ca5SDavid du Colombier ut->blocks[tslot] = ut->blocks[slot];
11159cc4ca5SDavid du Colombier ut->blocks[slot].data = d;
11259cc4ca5SDavid du Colombier tslot = slot;
11359cc4ca5SDavid du Colombier }
11459cc4ca5SDavid du Colombier ut->blocks[tslot].seq = seq;
115*9a747e4fSDavid du Colombier ut->blocks[tslot].maxoff = len;
11659cc4ca5SDavid du Colombier
11759cc4ca5SDavid du Colombier ut->slot++;
11859cc4ca5SDavid du Colombier if(ut->slot >= DWinBlocks)
11959cc4ca5SDavid du Colombier ut->slot = 0;
12059cc4ca5SDavid du Colombier
121*9a747e4fSDavid du Colombier ut->blocks[ut->slot].seq = ~0UL;
122*9a747e4fSDavid du Colombier ut->blocks[ut->slot].maxoff = 0;
123*9a747e4fSDavid du Colombier
124*9a747e4fSDavid du Colombier return tslot;
125*9a747e4fSDavid du Colombier }
126*9a747e4fSDavid du Colombier
127*9a747e4fSDavid du Colombier int
unthwackadd(Unthwack * ut,uchar * src,int nsrc,ulong seq)128*9a747e4fSDavid du Colombier unthwackadd(Unthwack *ut, uchar *src, int nsrc, ulong seq)
129*9a747e4fSDavid du Colombier {
130*9a747e4fSDavid du Colombier int tslot;
131*9a747e4fSDavid du Colombier
132*9a747e4fSDavid du Colombier if(nsrc > ThwMaxBlock)
133*9a747e4fSDavid du Colombier return -1;
134*9a747e4fSDavid du Colombier
135*9a747e4fSDavid du Colombier tslot = unthwackinsert(ut, nsrc, seq);
136*9a747e4fSDavid du Colombier if(tslot < 0)
137*9a747e4fSDavid du Colombier return -1;
138*9a747e4fSDavid du Colombier
139*9a747e4fSDavid du Colombier memmove(ut->blocks[tslot].data, src, nsrc);
140*9a747e4fSDavid du Colombier
14159cc4ca5SDavid du Colombier return nsrc;
14259cc4ca5SDavid du Colombier }
14359cc4ca5SDavid du Colombier
14459cc4ca5SDavid du Colombier int
unthwack(Unthwack * ut,uchar * dst,int ndst,uchar * src,int nsrc,ulong seq)1457dd7cddfSDavid du Colombier unthwack(Unthwack *ut, uchar *dst, int ndst, uchar *src, int nsrc, ulong seq)
1467dd7cddfSDavid du Colombier {
1477dd7cddfSDavid du Colombier UnthwBlock blocks[CompBlocks], *b, *eblocks;
1487dd7cddfSDavid du Colombier uchar *s, *d, *dmax, *smax, lit;
149*9a747e4fSDavid du Colombier ulong cmask, cseq, bseq, utbits;
150*9a747e4fSDavid du Colombier int i, off, len, bits, slot, use, code, utnbits, overbits, lithist;
1517dd7cddfSDavid du Colombier
1527dd7cddfSDavid du Colombier if(nsrc < 4 || nsrc > ThwMaxBlock){
1537dd7cddfSDavid du Colombier snprint(ut->err, ThwErrLen, "block too small or large");
1547dd7cddfSDavid du Colombier return -1;
1557dd7cddfSDavid du Colombier }
1567dd7cddfSDavid du Colombier
157*9a747e4fSDavid du Colombier slot = ut->slot;
1587dd7cddfSDavid du Colombier b = blocks;
159*9a747e4fSDavid du Colombier *b = ut->blocks[slot];
1607dd7cddfSDavid du Colombier d = b->data;
1617dd7cddfSDavid du Colombier dmax = d + ndst;
1627dd7cddfSDavid du Colombier
1637dd7cddfSDavid du Colombier /*
1647dd7cddfSDavid du Colombier * set up the history blocks
1657dd7cddfSDavid du Colombier */
1667dd7cddfSDavid du Colombier cseq = seq - src[0];
1677dd7cddfSDavid du Colombier cmask = src[1];
1687dd7cddfSDavid du Colombier b++;
1697dd7cddfSDavid du Colombier while(cseq != seq && b < blocks + CompBlocks){
1707dd7cddfSDavid du Colombier slot--;
1717dd7cddfSDavid du Colombier if(slot < 0)
1727dd7cddfSDavid du Colombier slot += DWinBlocks;
1737dd7cddfSDavid du Colombier if(slot == ut->slot)
1747dd7cddfSDavid du Colombier break;
1757dd7cddfSDavid du Colombier bseq = ut->blocks[slot].seq;
1767dd7cddfSDavid du Colombier if(bseq == cseq){
1777dd7cddfSDavid du Colombier *b = ut->blocks[slot];
1787dd7cddfSDavid du Colombier b++;
1797dd7cddfSDavid du Colombier if(cmask == 0){
1807dd7cddfSDavid du Colombier cseq = seq;
1817dd7cddfSDavid du Colombier break;
1827dd7cddfSDavid du Colombier }
1837dd7cddfSDavid du Colombier do{
1847dd7cddfSDavid du Colombier bits = cmask & 1;
1857dd7cddfSDavid du Colombier cseq--;
1867dd7cddfSDavid du Colombier cmask >>= 1;
1877dd7cddfSDavid du Colombier }while(!bits);
1887dd7cddfSDavid du Colombier }
1897dd7cddfSDavid du Colombier }
1907dd7cddfSDavid du Colombier eblocks = b;
1917dd7cddfSDavid du Colombier if(cseq != seq){
1927dd7cddfSDavid du Colombier snprint(ut->err, ThwErrLen, "blocks dropped: seq=%ld cseq=%ld %d cmask=%#lx %#x\n", seq, cseq, src[0], cmask, src[1]);
1937dd7cddfSDavid du Colombier return -2;
1947dd7cddfSDavid du Colombier }
1957dd7cddfSDavid du Colombier
1967dd7cddfSDavid du Colombier smax = src + nsrc;
1977dd7cddfSDavid du Colombier src += 2;
1987dd7cddfSDavid du Colombier utnbits = 0;
1997dd7cddfSDavid du Colombier utbits = 0;
2007dd7cddfSDavid du Colombier overbits = 0;
2017dd7cddfSDavid du Colombier lithist = ~0;
2027dd7cddfSDavid du Colombier while(src < smax || utnbits - overbits >= MinDecode){
2037dd7cddfSDavid du Colombier while(utnbits <= 24){
2047dd7cddfSDavid du Colombier utbits <<= 8;
2057dd7cddfSDavid du Colombier if(src < smax)
2067dd7cddfSDavid du Colombier utbits |= *src++;
2077dd7cddfSDavid du Colombier else
2087dd7cddfSDavid du Colombier overbits += 8;
2097dd7cddfSDavid du Colombier utnbits += 8;
2107dd7cddfSDavid du Colombier }
2117dd7cddfSDavid du Colombier
2127dd7cddfSDavid du Colombier /*
2137dd7cddfSDavid du Colombier * literal
2147dd7cddfSDavid du Colombier */
2157dd7cddfSDavid du Colombier len = lenval[(utbits >> (utnbits - 5)) & 0x1f];
2167dd7cddfSDavid du Colombier if(len == 0){
2177dd7cddfSDavid du Colombier if(lithist & 0xf){
2187dd7cddfSDavid du Colombier utnbits -= 9;
2197dd7cddfSDavid du Colombier lit = (utbits >> utnbits) & 0xff;
2207dd7cddfSDavid du Colombier lit &= 255;
2217dd7cddfSDavid du Colombier }else{
2227dd7cddfSDavid du Colombier utnbits -= 8;
2237dd7cddfSDavid du Colombier lit = (utbits >> utnbits) & 0x7f;
2247dd7cddfSDavid du Colombier if(lit < 32){
2257dd7cddfSDavid du Colombier if(lit < 24){
2267dd7cddfSDavid du Colombier utnbits -= 2;
2277dd7cddfSDavid du Colombier lit = (lit << 2) | ((utbits >> utnbits) & 3);
2287dd7cddfSDavid du Colombier }else{
2297dd7cddfSDavid du Colombier utnbits -= 3;
2307dd7cddfSDavid du Colombier lit = (lit << 3) | ((utbits >> utnbits) & 7);
2317dd7cddfSDavid du Colombier }
2327dd7cddfSDavid du Colombier lit = (lit - 64) & 0xff;
2337dd7cddfSDavid du Colombier }
2347dd7cddfSDavid du Colombier }
23580ee5cbfSDavid du Colombier if(d >= dmax){
23680ee5cbfSDavid du Colombier snprint(ut->err, ThwErrLen, "too much output");
23780ee5cbfSDavid du Colombier return -1;
23880ee5cbfSDavid du Colombier }
2397dd7cddfSDavid du Colombier *d++ = lit;
2407dd7cddfSDavid du Colombier lithist = (lithist << 1) | (lit < 32) | (lit > 127);
2417dd7cddfSDavid du Colombier blocks->maxoff++;
2427dd7cddfSDavid du Colombier continue;
2437dd7cddfSDavid du Colombier }
2447dd7cddfSDavid du Colombier
2457dd7cddfSDavid du Colombier /*
2467dd7cddfSDavid du Colombier * length
2477dd7cddfSDavid du Colombier */
2487dd7cddfSDavid du Colombier if(len < 255)
2497dd7cddfSDavid du Colombier utnbits -= lenbits[len];
2507dd7cddfSDavid du Colombier else{
2517dd7cddfSDavid du Colombier utnbits -= DBigLenBits;
2527dd7cddfSDavid du Colombier code = ((utbits >> utnbits) & ((1 << DBigLenBits) - 1)) - DBigLenCode;
2537dd7cddfSDavid du Colombier len = DMaxFastLen;
2547dd7cddfSDavid du Colombier use = DBigLenBase;
2557dd7cddfSDavid du Colombier bits = (DBigLenBits & 1) ^ 1;
2567dd7cddfSDavid du Colombier while(code >= use){
2577dd7cddfSDavid du Colombier len += use;
2587dd7cddfSDavid du Colombier code -= use;
2597dd7cddfSDavid du Colombier code <<= 1;
2607dd7cddfSDavid du Colombier utnbits--;
26159cc4ca5SDavid du Colombier if(utnbits < 0){
26259cc4ca5SDavid du Colombier snprint(ut->err, ThwErrLen, "len out of range");
26359cc4ca5SDavid du Colombier return -1;
26459cc4ca5SDavid du Colombier }
2657dd7cddfSDavid du Colombier code |= (utbits >> utnbits) & 1;
2667dd7cddfSDavid du Colombier use <<= bits;
2677dd7cddfSDavid du Colombier bits ^= 1;
2687dd7cddfSDavid du Colombier }
2697dd7cddfSDavid du Colombier len += code;
2707dd7cddfSDavid du Colombier
2717dd7cddfSDavid du Colombier while(utnbits <= 24){
2727dd7cddfSDavid du Colombier utbits <<= 8;
2737dd7cddfSDavid du Colombier if(src < smax)
2747dd7cddfSDavid du Colombier utbits |= *src++;
2757dd7cddfSDavid du Colombier else
2767dd7cddfSDavid du Colombier overbits += 8;
2777dd7cddfSDavid du Colombier utnbits += 8;
2787dd7cddfSDavid du Colombier }
2797dd7cddfSDavid du Colombier }
2807dd7cddfSDavid du Colombier
2817dd7cddfSDavid du Colombier /*
2827dd7cddfSDavid du Colombier * offset
2837dd7cddfSDavid du Colombier */
2847dd7cddfSDavid du Colombier utnbits -= 4;
2857dd7cddfSDavid du Colombier bits = (utbits >> utnbits) & 0xf;
2867dd7cddfSDavid du Colombier off = offbase[bits];
2877dd7cddfSDavid du Colombier bits = offbits[bits];
2887dd7cddfSDavid du Colombier
2897dd7cddfSDavid du Colombier utnbits -= bits;
2907dd7cddfSDavid du Colombier off |= (utbits >> utnbits) & ((1 << bits) - 1);
2917dd7cddfSDavid du Colombier off++;
2927dd7cddfSDavid du Colombier
2937dd7cddfSDavid du Colombier b = blocks;
2947dd7cddfSDavid du Colombier while(off > b->maxoff){
2957dd7cddfSDavid du Colombier off -= b->maxoff;
2967dd7cddfSDavid du Colombier b++;
2977dd7cddfSDavid du Colombier if(b >= eblocks){
2987dd7cddfSDavid du Colombier snprint(ut->err, ThwErrLen, "offset out of range");
2997dd7cddfSDavid du Colombier return -1;
3007dd7cddfSDavid du Colombier }
3017dd7cddfSDavid du Colombier }
3027dd7cddfSDavid du Colombier if(d + len > dmax
3037dd7cddfSDavid du Colombier || b != blocks && len > off){
3047dd7cddfSDavid du Colombier snprint(ut->err, ThwErrLen, "len out of range");
3057dd7cddfSDavid du Colombier return -1;
3067dd7cddfSDavid du Colombier }
3077dd7cddfSDavid du Colombier s = b->data + b->maxoff - off;
3087dd7cddfSDavid du Colombier blocks->maxoff += len;
3097dd7cddfSDavid du Colombier
3107dd7cddfSDavid du Colombier for(i = 0; i < len; i++)
3117dd7cddfSDavid du Colombier d[i] = s[i];
3127dd7cddfSDavid du Colombier d += len;
3137dd7cddfSDavid du Colombier }
3147dd7cddfSDavid du Colombier if(utnbits < overbits){
3157dd7cddfSDavid du Colombier snprint(ut->err, ThwErrLen, "compressed data overrun");
3167dd7cddfSDavid du Colombier return -1;
3177dd7cddfSDavid du Colombier }
3187dd7cddfSDavid du Colombier
3197dd7cddfSDavid du Colombier len = d - blocks->data;
3207dd7cddfSDavid du Colombier memmove(dst, blocks->data, len);
3217dd7cddfSDavid du Colombier
322*9a747e4fSDavid du Colombier unthwackinsert(ut, len, seq);
3237dd7cddfSDavid du Colombier
3247dd7cddfSDavid du Colombier return len;
3257dd7cddfSDavid du Colombier }
326