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
typedef struct Cstate Cstate;
9
struct Cstate
10
{
11
	ulong		seq;
12
	Thwack		th;
13
	ulong		stats[ThwStats];
14
};
15
 
16
typedef struct Uncstate Uncstate;
17
struct Uncstate
18
{
19
	QLock		ackl;			/* lock for acks sent back to compressor */
20
	int		doack;			/* send an ack? */
21
	int		badpacks;		/* bad packets seen in a row */
22
	ulong		ackseq;			/* packets to ack */
23
	int		ackmask;
24
 
25
	int		active;			/* 0 => waiting for resetack */
26
	int		resetid;		/* id of most recent reset */
27
	Unthwack	ut;
28
};
29
 
30
enum
31
{
32
	ThwAcked	= 1UL << 23,
33
	ThwCompMask	= 3UL << 21,
34
	ThwCompressed	= 0UL << 21,
35
	ThwUncomp	= 1UL << 21,
36
	ThwUncompAdd	= 2UL << 21,		/* uncompressed, but add to decompression buffer */
37
	ThwSeqMask	= 0x0fffff,
38
	ThwSmallPack	= 96,
39
};
40
 
41
static	void		*compinit(PPP*);
42
static	Block*		comp(PPP*, ushort, Block*, int*);
43
static	Block		*compresetreq(void*, Block*);
44
static	void		compcompack(void*, Block*);
45
static	void		compfini(void*);
46
 
47
static	void		*uncinit(PPP*);
48
static	Block*		uncomp(PPP*, Block*, int *protop, Block**);
49
static	void		uncfini(void*);
50
static	void		uncresetack(void*, Block*);
51
 
52
Comptype cthwack = {
53
	compinit,
54
	comp,
55
	compresetreq,
56
	compfini
57
};
58
 
59
Uncomptype uncthwack = {
60
	uncinit,
61
	uncomp,
62
	uncresetack,
63
	uncfini
64
};
65
 
66
static void *
67
compinit(PPP *)
68
{
69
	Cstate *cs;
70
 
71
	cs = mallocz(sizeof(Cstate), 1);
72
	thwackinit(&cs->th);
73
	return cs;
74
}
75
 
76
static void
77
compfini(void *as)
78
{
79
	Cstate *cs;
80
 
81
	cs = as;
82
	thwackcleanup(&cs->th);
83
	free(cs);
84
}
85
 
86
 
87
static Block *
88
compresetreq(void *as, Block *b)
89
{
90
	Cstate *cs;
91
	Lcpmsg *m;
92
	int id;
93
 
94
	cs = as;
95
	m = (Lcpmsg*)b->rptr;
96
	id = m->id;
97
 
98
	thwackinit(&cs->th);
99
 
100
	freeb(b);
101
 
102
	netlog("thwack resetreq id=%d \n", id);
103
 
104
	b = alloclcp(Lresetack, id, 4, &m);
105
	hnputs(m->len, 4);
106
 
107
	return b;
108
}
109
 
110
static Block*
111
comp(PPP *ppp, ushort proto, Block *b, int *protop)
112
{
113
	Uncstate *uncs;
114
	Cstate *cs;
115
	Block *bb;
116
	ulong seq, acked;
117
	int n, nn, mustadd;
118
 
119
	cs = ppp->cstate;
120
	*protop = 0;
121
 
122
	/* put ack and protocol into b */
123
	n = BLEN(b);
124
	if(b->rptr - (2+4) < b->base)
125
		sysfatal("thwack: not enough header in block");
126
	acked = 0;
127
	if(ppp->unctype == &uncthwack){
128
		uncs = ppp->uncstate;
129
		qlock(&uncs->ackl);
130
		if(uncs->doack){
131
			uncs->doack = 0;
132
			b->rptr -= 4;
133
			b->rptr[0] = uncs->ackseq >> 16;
134
			b->rptr[1] = uncs->ackseq >> 8;
135
			b->rptr[2] = uncs->ackseq;
136
			b->rptr[3] = uncs->ackmask;
137
			acked = ThwAcked;
138
		}
139
		qunlock(&uncs->ackl);
140
	}
141
	if(proto > 0xff){
142
		b->rptr -= 2;
143
		b->rptr[0] = proto >> 8;
144
		b->rptr[1] = proto;
145
	}else{
146
		b->rptr--;
147
		b->rptr[0] = proto;
148
	}
149
 
150
	bb = allocb(BLEN(b) + 3);
151
 
152
	seq = cs->seq;
153
	if(n <= 3){
154
		mustadd = 0;
155
		nn = -1;
156
	}else{
157
		mustadd = n < ThwSmallPack;
158
		nn = thwack(&cs->th, mustadd, bb->wptr + 3, n - 3, b, seq, cs->stats);
159
	}
160
	if(nn < 0 && !mustadd){
161
		if(!acked || BLEN(b) + 1 > ppp->mtu){
162
			freeb(bb);
163
			if(acked)
164
				b->rptr += 4;
165
			if(proto > 0xff)
166
				b->rptr += 2;
167
			else
168
				b->rptr++;
169
			*protop = proto;
170
			return b;
171
		}
172
		bb->wptr[0] = (ThwUncomp | ThwAcked) >> 16;
173
 
174
		memmove(bb->wptr + 1, b->rptr, BLEN(b));
175
 
176
		bb->wptr += BLEN(b) + 1;
177
		freeb(b);
178
	}else{
179
		cs->seq = (seq + 1) & ThwSeqMask;
180
		if(nn < 0){
181
			nn = BLEN(b);
182
			memmove(bb->wptr + 3, b->rptr, nn);
183
			seq |= ThwUncompAdd;
184
		}else
185
			seq |= ThwCompressed;
186
		seq |= acked;
187
		bb->wptr[0] = seq>>16;
188
		bb->wptr[1] = seq>>8;
189
		bb->wptr[2] = seq;
190
 
191
		bb->wptr += nn + 3;
192
	}
193
 
194
	*protop = Pcdata;
195
	return bb;
196
}
197
 
198
static	void *
199
uncinit(PPP *)
200
{
201
	Uncstate *s;
202
 
203
	s = mallocz(sizeof(Uncstate), 1);
204
 
205
	s->active = 1;
206
 
207
	unthwackinit(&s->ut);
208
 
209
	return s;
210
}
211
 
212
static	void
213
uncfini(void *as)
214
{
215
	free(as);
216
}
217
 
218
static	void
219
uncresetack(void *as, Block *b)
220
{
221
	Uncstate *s;
222
	Lcpmsg *m;
223
 
224
	s = as;
225
	m = (Lcpmsg*)b->rptr;
226
 
227
	/*
228
	 * rfc 1962 says we must reset every message
229
	 * we don't since we may have acked some messages
230
	 * which the compressor will use in the future.
231
	 */
232
	netlog("unthwack resetack id=%d resetid=%d active=%d\n", m->id, s->resetid, s->active);
233
	if(m->id == (uchar)s->resetid && !s->active){
234
		s->active = 1;
235
		unthwackinit(&s->ut);
236
	}
237
}
238
 
239
static	Block*
240
uncomp(PPP *ppp, Block *bb, int *protop, Block **reply)
241
{
242
	Lcpmsg *m;
243
	Cstate *cs;
244
	Uncstate *uncs;
245
	Block *b, *r;
246
	ulong seq, mseq;
247
	ushort proto;
248
	uchar mask;
249
	int n;
250
 
251
	*reply = nil;
252
	*protop = 0;
253
	uncs = ppp->uncstate;
254
 
255
	if(BLEN(bb) < 4){
256
		syslog(0, "ppp", ": thwack: short packet\n");
257
		freeb(bb);
258
		return nil;
259
	}
260
 
261
	if(!uncs->active){
262
		netlog("unthwack: inactive, killing packet\n");
263
		freeb(bb);
264
		r = alloclcp(Lresetreq, uncs->resetid, 4, &m);
265
		hnputs(m->len, 4);
266
		*reply = r;
267
		return nil;
268
	}
269
 
270
	seq = bb->rptr[0] << 16;
271
	if((seq & ThwCompMask) == ThwUncomp){
272
		bb->rptr++;
273
		b = bb;
274
	}else{
275
		seq |= (bb->rptr[1]<<8) | bb->rptr[2];
276
		bb->rptr += 3;
277
		if((seq & ThwCompMask) == ThwCompressed){
278
			b = allocb(ThwMaxBlock);
279
			n = unthwack(&uncs->ut, b->wptr, ThwMaxBlock, bb->rptr, BLEN(bb), seq & ThwSeqMask);
280
			freeb(bb);
281
			if(n < 2){
282
				syslog(0, "ppp", ": unthwack: short or corrupted packet %d seq=%ld\n", n, seq);
283
				netlog("unthwack: short or corrupted packet n=%d seq=%ld: %s\n", n, seq, uncs->ut.err);
284
				freeb(b);
285
 
286
				r = alloclcp(Lresetreq, ++uncs->resetid, 4, &m);
287
				hnputs(m->len, 4);
288
				*reply = r;
289
				uncs->active = 0;
290
				return nil;
291
			}
292
			b->wptr += n;
293
		}else{
294
			unthwackadd(&uncs->ut, bb->rptr, BLEN(bb), seq & ThwSeqMask);
295
			b = bb;
296
		}
297
 
298
		/*
299
		 * update ack state
300
		 */
301
		mseq = unthwackstate(&uncs->ut, &mask);
302
		qlock(&uncs->ackl);
303
		uncs->ackseq = mseq;
304
		uncs->ackmask = mask;
305
		uncs->doack = 1;
306
		qunlock(&uncs->ackl);
307
	}
308
 
309
	/*
310
	 * grab the compressed protocol field
311
	 */
312
	proto = *b->rptr++;
313
	if((proto & 1) == 0)
314
		proto = (proto << 8) | *b->rptr++;
315
	*protop = proto;
316
 
317
	/*
318
	 * decode the ack, and forward to compressor
319
	 */
320
	if(seq & ThwAcked){
321
		if(ppp->ctype == &cthwack){
322
			cs = ppp->cstate;
323
			mseq = (b->rptr[0]<<16) | (b->rptr[1]<<8) | b->rptr[2];
324
			mask = b->rptr[3];
325
			thwackack(&cs->th, mseq, mask);
326
		}
327
		b->rptr += 4;
328
	}
329
	return b;
330
}