Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include <u.h>
2
#include <libc.h>
3
#include <ip.h>
4
#include <auth.h>
5
#include "ppp.h"
6
#include "thwack.h"
7
 
8
enum
9
{
10
	DMaxFastLen	= 7,
11
	DBigLenCode	= 0x3c,		/* minimum code for large lenth encoding */
12
	DBigLenBits	= 6,
13
	DBigLenBase	= 1		/* starting items to encode for big lens */
14
};
15
 
16
static uchar lenval[1 << (DBigLenBits - 1)] =
17
{
18
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
19
	3, 3, 3, 3, 3, 3, 3, 3,
20
	4, 4, 4, 4,
21
	5,
22
	6,
23
	255,
24
	255
25
};
26
 
27
static uchar lenbits[] =
28
{
29
	0, 0, 0,
30
	2, 3, 5, 5,
31
};
32
 
33
static uchar offbits[16] =
34
{
35
	5, 5, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 12, 13
36
};
37
 
38
static ushort offbase[16] =
39
{
40
	0, 0x20,
41
	0x40, 0x60,
42
	0x80, 0xc0,
43
	0x100, 0x180,
44
	0x200, 0x300,
45
	0x400, 0x600,
46
	0x800, 0xc00,
47
	0x1000,
48
	0x2000
49
};
50
 
51
void
52
unthwackinit(Unthwack *ut)
53
{
54
	int i;
55
 
56
	memset(ut, 0, sizeof *ut);
57
	for(i = 0; i < DWinBlocks; i++)
58
		ut->blocks[i].data = ut->data[i];
59
}
60
 
61
ulong
62
unthwackstate(Unthwack *ut, uchar *mask)
63
{
64
	ulong bseq, seq;
65
	int slot, m;
66
 
67
	seq = ~0UL;
68
	m = 0;
69
	slot = ut->slot;
70
	for(;;){
71
		slot--;
72
		if(slot < 0)
73
			slot += DWinBlocks;
74
		if(slot == ut->slot)
75
			break;
76
		if(ut->blocks[slot].maxoff == 0)
77
			continue;
78
		bseq = ut->blocks[slot].seq;
79
		if(seq == ~0UL)
80
			seq = bseq;
81
		else if(seq - bseq > MaxSeqMask)
82
			break;
83
		else
84
			m |= 1 << (seq - bseq - 1);
85
	}
86
	*mask = m;
87
	return seq;
88
}
89
 
90
/*
91
 * insert this block in it's correct sequence number order.
92
 * replace the oldest block, which is always pointed to by ut->slot.
93
 * the encoder doesn't use a history at wraparound,
94
 * so don't worry about that case.
95
 */
96
static int
97
unthwackinsert(Unthwack *ut, int len, ulong seq)
98
{
99
	uchar *d;
100
	int slot, tslot;
101
 
102
	tslot = ut->slot;
103
	for(;;){
104
		slot = tslot - 1;
105
		if(slot < 0)
106
			slot += DWinBlocks;
107
		if(ut->blocks[slot].seq <= seq || ut->blocks[slot].maxoff == 0)
108
			break;
109
		d = ut->blocks[tslot].data;
110
		ut->blocks[tslot] = ut->blocks[slot];
111
		ut->blocks[slot].data = d;
112
		tslot = slot;
113
	}
114
	ut->blocks[tslot].seq = seq;
115
	ut->blocks[tslot].maxoff = len;
116
 
117
	ut->slot++;
118
	if(ut->slot >= DWinBlocks)
119
		ut->slot = 0;
120
 
121
	ut->blocks[ut->slot].seq = ~0UL;
122
	ut->blocks[ut->slot].maxoff = 0;
123
 
124
	return tslot;
125
}
126
 
127
int
128
unthwackadd(Unthwack *ut, uchar *src, int nsrc, ulong seq)
129
{
130
	int tslot;
131
 
132
	if(nsrc > ThwMaxBlock)
133
		return -1;
134
 
135
	tslot = unthwackinsert(ut, nsrc, seq);
136
	if(tslot < 0)
137
		return -1;
138
 
139
	memmove(ut->blocks[tslot].data, src, nsrc);
140
 
141
	return nsrc;
142
}
143
 
144
int
145
unthwack(Unthwack *ut, uchar *dst, int ndst, uchar *src, int nsrc, ulong seq)
146
{
147
	UnthwBlock blocks[CompBlocks], *b, *eblocks;
148
	uchar *s, *d, *dmax, *smax, lit;
149
	ulong cmask, cseq, bseq, utbits;
150
	int i, off, len, bits, slot, use, code, utnbits, overbits, lithist;
151
 
152
	if(nsrc < 4 || nsrc > ThwMaxBlock){
153
		snprint(ut->err, ThwErrLen, "block too small or large");
154
		return -1;
155
	}
156
 
157
	slot = ut->slot;
158
	b = blocks;
159
	*b = ut->blocks[slot];
160
	d = b->data;
161
	dmax = d + ndst;
162
 
163
	/*
164
	 * set up the history blocks
165
	 */
166
	cseq = seq - src[0];
167
	cmask = src[1];
168
	b++;
169
	while(cseq != seq && b < blocks + CompBlocks){
170
		slot--;
171
		if(slot < 0)
172
			slot += DWinBlocks;
173
		if(slot == ut->slot)
174
			break;
175
		bseq = ut->blocks[slot].seq;
176
		if(bseq == cseq){
177
			*b = ut->blocks[slot];
178
			b++;
179
			if(cmask == 0){
180
				cseq = seq;
181
				break;
182
			}
183
			do{
184
				bits = cmask & 1;
185
				cseq--;
186
				cmask >>= 1;
187
			}while(!bits);
188
		}
189
	}
190
	eblocks = b;
191
	if(cseq != seq){
192
		snprint(ut->err, ThwErrLen, "blocks dropped: seq=%ld cseq=%ld %d cmask=%#lx %#x\n", seq, cseq, src[0], cmask, src[1]);
193
		return -2;
194
	}
195
 
196
	smax = src + nsrc;
197
	src += 2;
198
	utnbits = 0;
199
	utbits = 0;
200
	overbits = 0;
201
	lithist = ~0;
202
	while(src < smax || utnbits - overbits >= MinDecode){
203
		while(utnbits <= 24){
204
			utbits <<= 8;
205
			if(src < smax)
206
				utbits |= *src++;
207
			else
208
				overbits += 8;
209
			utnbits += 8;
210
		}
211
 
212
		/*
213
		 * literal
214
		 */
215
		len = lenval[(utbits >> (utnbits - 5)) & 0x1f];
216
		if(len == 0){
217
			if(lithist & 0xf){
218
				utnbits -= 9;
219
				lit = (utbits >> utnbits) & 0xff;
220
				lit &= 255;
221
			}else{
222
				utnbits -= 8;
223
				lit = (utbits >> utnbits) & 0x7f;
224
				if(lit < 32){
225
					if(lit < 24){
226
						utnbits -= 2;
227
						lit = (lit << 2) | ((utbits >> utnbits) & 3);
228
					}else{
229
						utnbits -= 3;
230
						lit = (lit << 3) | ((utbits >> utnbits) & 7);
231
					}
232
					lit = (lit - 64) & 0xff;
233
				}
234
			}
235
			if(d >= dmax){
236
				snprint(ut->err, ThwErrLen, "too much output");
237
				return -1;
238
			}
239
			*d++ = lit;
240
			lithist = (lithist << 1) | (lit < 32) | (lit > 127);
241
			blocks->maxoff++;
242
			continue;
243
		}
244
 
245
		/*
246
		 * length
247
		 */
248
		if(len < 255)
249
			utnbits -= lenbits[len];
250
		else{
251
			utnbits -= DBigLenBits;
252
			code = ((utbits >> utnbits) & ((1 << DBigLenBits) - 1)) - DBigLenCode;
253
			len = DMaxFastLen;
254
			use = DBigLenBase;
255
			bits = (DBigLenBits & 1) ^ 1;
256
			while(code >= use){
257
				len += use;
258
				code -= use;
259
				code <<= 1;
260
				utnbits--;
261
				if(utnbits < 0){
262
					snprint(ut->err, ThwErrLen, "len out of range");
263
					return -1;
264
				}
265
				code |= (utbits >> utnbits) & 1;
266
				use <<= bits;
267
				bits ^= 1;
268
			}
269
			len += code;
270
 
271
			while(utnbits <= 24){
272
				utbits <<= 8;
273
				if(src < smax)
274
					utbits |= *src++;
275
				else
276
					overbits += 8;
277
				utnbits += 8;
278
			}
279
		}
280
 
281
		/*
282
		 * offset
283
		 */
284
		utnbits -= 4;
285
		bits = (utbits >> utnbits) & 0xf;
286
		off = offbase[bits];
287
		bits = offbits[bits];
288
 
289
		utnbits -= bits;
290
		off |= (utbits >> utnbits) & ((1 << bits) - 1);
291
		off++;
292
 
293
		b = blocks;
294
		while(off > b->maxoff){
295
			off -= b->maxoff;
296
			b++;
297
			if(b >= eblocks){
298
				snprint(ut->err, ThwErrLen, "offset out of range");
299
				return -1;
300
			}
301
		}
302
		if(d + len > dmax
303
		|| b != blocks && len > off){
304
			snprint(ut->err, ThwErrLen, "len out of range");
305
			return -1;
306
		}
307
		s = b->data + b->maxoff - off;
308
		blocks->maxoff += len;
309
 
310
		for(i = 0; i < len; i++)
311
			d[i] = s[i];
312
		d += len;
313
	}
314
	if(utnbits < overbits){
315
		snprint(ut->err, ThwErrLen, "compressed data overrun");
316
		return -1;
317
	}
318
 
319
	len = d - blocks->data;
320
	memmove(dst, blocks->data, len);
321
 
322
	unthwackinsert(ut, len, seq);
323
 
324
	return len;
325
}