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 *
compinit(PPP *)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
compfini(void * as)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 *
compresetreq(void * as,Block * b)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*
comp(PPP * ppp,ushort proto,Block * b,int * protop)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 *
uncinit(PPP *)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
uncfini(void * as)213 uncfini(void *as)
214 {
215 free(as);
216 }
217
218 static void
uncresetack(void * as,Block * b)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*
uncomp(PPP * ppp,Block * bb,int * protop,Block ** reply)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 }
331