1 | /*- |
---|
2 | * Copyright (c) 1989, 1993, 1994 |
---|
3 | * The Regents of the University of California. All rights reserved. |
---|
4 | * |
---|
5 | * Redistribution and use in source and binary forms, with or without |
---|
6 | * modification, are permitted provided that the following conditions |
---|
7 | * are met: |
---|
8 | * 1. Redistributions of source code must retain the above copyright |
---|
9 | * notice, this list of conditions and the following disclaimer. |
---|
10 | * 2. Redistributions in binary form must reproduce the above copyright |
---|
11 | * notice, this list of conditions and the following disclaimer in the |
---|
12 | * documentation and/or other materials provided with the distribution. |
---|
13 | * 4. Neither the name of the University nor the names of its contributors |
---|
14 | * may be used to endorse or promote products derived from this software |
---|
15 | * without specific prior written permission. |
---|
16 | * |
---|
17 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
---|
18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
---|
19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
---|
20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
---|
21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
---|
22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
---|
23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
---|
24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
---|
25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
---|
26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
---|
27 | * SUCH DAMAGE. |
---|
28 | * |
---|
29 | * @(#)slcompress.c 8.2 (Berkeley) 4/16/94 |
---|
30 | * $FreeBSD: src/sys/net/slcompress.c,v 1.19 2004/04/07 20:46:12 imp Exp $ |
---|
31 | */ |
---|
32 | |
---|
33 | /* |
---|
34 | * Routines to compress and uncompess tcp packets (for transmission |
---|
35 | * over low speed serial lines. |
---|
36 | * |
---|
37 | * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989: |
---|
38 | * - Initial distribution. |
---|
39 | * |
---|
40 | */ |
---|
41 | |
---|
42 | #if defined(__rtems__) |
---|
43 | #include <stdint.h> |
---|
44 | #endif |
---|
45 | |
---|
46 | #include <sys/param.h> |
---|
47 | #include <sys/mbuf.h> |
---|
48 | #include <sys/systm.h> |
---|
49 | |
---|
50 | #include <netinet/in.h> |
---|
51 | #include <netinet/in_systm.h> |
---|
52 | #include <netinet/ip.h> |
---|
53 | #include <netinet/tcp.h> |
---|
54 | |
---|
55 | #include <net/slcompress.h> |
---|
56 | |
---|
57 | #ifndef SL_NO_STATS |
---|
58 | #define INCR(counter) ++comp->counter; |
---|
59 | #else |
---|
60 | #define INCR(counter) |
---|
61 | #endif |
---|
62 | |
---|
63 | #define BCMP(p1, p2, n) bcmp((void *)(p1), (void *)(p2), (int)(n)) |
---|
64 | #define BCOPY(p1, p2, n) bcopy((void *)(p1), (void *)(p2), (int)(n)) |
---|
65 | |
---|
66 | void |
---|
67 | sl_compress_init(comp, max_state) |
---|
68 | struct slcompress *comp; |
---|
69 | int max_state; |
---|
70 | { |
---|
71 | register u_int i; |
---|
72 | register struct cstate *tstate = comp->tstate; |
---|
73 | |
---|
74 | if (max_state == -1) { |
---|
75 | max_state = MAX_STATES - 1; |
---|
76 | bzero((char *)comp, sizeof(*comp)); |
---|
77 | } else { |
---|
78 | /* Don't reset statistics */ |
---|
79 | bzero((char *)comp->tstate, sizeof(comp->tstate)); |
---|
80 | bzero((char *)comp->rstate, sizeof(comp->rstate)); |
---|
81 | } |
---|
82 | for (i = max_state; i > 0; --i) { |
---|
83 | tstate[i].cs_id = i; |
---|
84 | tstate[i].cs_next = &tstate[i - 1]; |
---|
85 | } |
---|
86 | tstate[0].cs_next = &tstate[max_state]; |
---|
87 | tstate[0].cs_id = 0; |
---|
88 | comp->last_cs = &tstate[0]; |
---|
89 | comp->last_recv = 255; |
---|
90 | comp->last_xmit = 255; |
---|
91 | comp->flags = SLF_TOSS; |
---|
92 | } |
---|
93 | |
---|
94 | |
---|
95 | /* ENCODE encodes a number that is known to be non-zero. ENCODEZ |
---|
96 | * checks for zero (since zero has to be encoded in the long, 3 byte |
---|
97 | * form). |
---|
98 | */ |
---|
99 | #define ENCODE(n) { \ |
---|
100 | if ((u_int16_t)(n) >= 256) { \ |
---|
101 | *cp++ = 0; \ |
---|
102 | cp[1] = (n); \ |
---|
103 | cp[0] = (n) >> 8; \ |
---|
104 | cp += 2; \ |
---|
105 | } else { \ |
---|
106 | *cp++ = (n); \ |
---|
107 | } \ |
---|
108 | } |
---|
109 | #define ENCODEZ(n) { \ |
---|
110 | if ((u_int16_t)(n) >= 256 || (u_int16_t)(n) == 0) { \ |
---|
111 | *cp++ = 0; \ |
---|
112 | cp[1] = (n); \ |
---|
113 | cp[0] = (n) >> 8; \ |
---|
114 | cp += 2; \ |
---|
115 | } else { \ |
---|
116 | *cp++ = (n); \ |
---|
117 | } \ |
---|
118 | } |
---|
119 | |
---|
120 | #define DECODEL(f) { \ |
---|
121 | if (*cp == 0) {\ |
---|
122 | (f) = htonl(ntohl(f) + ((cp[1] << 8) | cp[2])); \ |
---|
123 | cp += 3; \ |
---|
124 | } else { \ |
---|
125 | (f) = htonl(ntohl(f) + (u_int32_t)*cp++); \ |
---|
126 | } \ |
---|
127 | } |
---|
128 | |
---|
129 | #define DECODES(f) { \ |
---|
130 | if (*cp == 0) {\ |
---|
131 | (f) = htons(ntohs(f) + ((cp[1] << 8) | cp[2])); \ |
---|
132 | cp += 3; \ |
---|
133 | } else { \ |
---|
134 | (f) = htons(ntohs(f) + (u_int32_t)*cp++); \ |
---|
135 | } \ |
---|
136 | } |
---|
137 | |
---|
138 | #define DECODEU(f) { \ |
---|
139 | if (*cp == 0) {\ |
---|
140 | (f) = htons((cp[1] << 8) | cp[2]); \ |
---|
141 | cp += 3; \ |
---|
142 | } else { \ |
---|
143 | (f) = htons((u_int32_t)*cp++); \ |
---|
144 | } \ |
---|
145 | } |
---|
146 | |
---|
147 | /* |
---|
148 | * Attempt to compress an outgoing TCP packet and return the type of |
---|
149 | * the result. The caller must have already verified that the protocol |
---|
150 | * is TCP. The first mbuf must contain the complete IP and TCP headers, |
---|
151 | * and "ip" must be == mtod(m, struct ip *). "comp" supplies the |
---|
152 | * compression state, and "compress_cid" tells us whether it is OK |
---|
153 | * to leave out the CID field when feasible. |
---|
154 | * |
---|
155 | * The caller is responsible for adjusting m->m_pkthdr.len upon return, |
---|
156 | * if m is an M_PKTHDR mbuf. |
---|
157 | */ |
---|
158 | u_int |
---|
159 | sl_compress_tcp(m, ip, comp, compress_cid) |
---|
160 | struct mbuf *m; |
---|
161 | register struct ip *ip; |
---|
162 | struct slcompress *comp; |
---|
163 | int compress_cid; |
---|
164 | { |
---|
165 | register struct cstate *cs = comp->last_cs->cs_next; |
---|
166 | register u_int hlen = ip->ip_hl; |
---|
167 | register struct tcphdr *oth; |
---|
168 | register struct tcphdr *th; |
---|
169 | register u_int deltaS, deltaA; |
---|
170 | register u_int changes = 0; |
---|
171 | u_char new_seq[16]; |
---|
172 | register u_char *cp = new_seq; |
---|
173 | |
---|
174 | /* |
---|
175 | * Bail if this is an IP fragment or if the TCP packet isn't |
---|
176 | * `compressible' (i.e., ACK isn't set or some other control bit is |
---|
177 | * set). (We assume that the caller has already made sure the |
---|
178 | * packet is IP proto TCP). |
---|
179 | */ |
---|
180 | if ((ip->ip_off & htons(0x3fff)) || m->m_len < 40) |
---|
181 | return (TYPE_IP); |
---|
182 | |
---|
183 | th = (struct tcphdr *)&((int32_t *)ip)[hlen]; |
---|
184 | if ((th->th_flags & (TH_SYN|TH_FIN|TH_RST|TH_ACK)) != TH_ACK) |
---|
185 | return (TYPE_IP); |
---|
186 | /* |
---|
187 | * Packet is compressible -- we're going to send either a |
---|
188 | * COMPRESSED_TCP or UNCOMPRESSED_TCP packet. Either way we need |
---|
189 | * to locate (or create) the connection state. Special case the |
---|
190 | * most recently used connection since it's most likely to be used |
---|
191 | * again & we don't have to do any reordering if it's used. |
---|
192 | */ |
---|
193 | INCR(sls_packets) |
---|
194 | if (ip->ip_src.s_addr != cs->cs_ip.ip_src.s_addr || |
---|
195 | ip->ip_dst.s_addr != cs->cs_ip.ip_dst.s_addr || |
---|
196 | *(int32_t *)th != ((int32_t *)&cs->cs_ip)[cs->cs_ip.ip_hl]) { |
---|
197 | /* |
---|
198 | * Wasn't the first -- search for it. |
---|
199 | * |
---|
200 | * States are kept in a circularly linked list with |
---|
201 | * last_cs pointing to the end of the list. The |
---|
202 | * list is kept in lru order by moving a state to the |
---|
203 | * head of the list whenever it is referenced. Since |
---|
204 | * the list is short and, empirically, the connection |
---|
205 | * we want is almost always near the front, we locate |
---|
206 | * states via linear search. If we don't find a state |
---|
207 | * for the datagram, the oldest state is (re-)used. |
---|
208 | */ |
---|
209 | register struct cstate *lcs; |
---|
210 | register struct cstate *lastcs = comp->last_cs; |
---|
211 | |
---|
212 | do { |
---|
213 | lcs = cs; cs = cs->cs_next; |
---|
214 | INCR(sls_searches) |
---|
215 | if (ip->ip_src.s_addr == cs->cs_ip.ip_src.s_addr |
---|
216 | && ip->ip_dst.s_addr == cs->cs_ip.ip_dst.s_addr |
---|
217 | && *(int32_t *)th == |
---|
218 | ((int32_t *)&cs->cs_ip)[cs->cs_ip.ip_hl]) |
---|
219 | goto found; |
---|
220 | } while (cs != lastcs); |
---|
221 | |
---|
222 | /* |
---|
223 | * Didn't find it -- re-use oldest cstate. Send an |
---|
224 | * uncompressed packet that tells the other side what |
---|
225 | * connection number we're using for this conversation. |
---|
226 | * Note that since the state list is circular, the oldest |
---|
227 | * state points to the newest and we only need to set |
---|
228 | * last_cs to update the lru linkage. |
---|
229 | */ |
---|
230 | INCR(sls_misses) |
---|
231 | comp->last_cs = lcs; |
---|
232 | hlen += th->th_off; |
---|
233 | hlen <<= 2; |
---|
234 | if (hlen > m->m_len) |
---|
235 | return TYPE_IP; |
---|
236 | goto uncompressed; |
---|
237 | |
---|
238 | found: |
---|
239 | /* |
---|
240 | * Found it -- move to the front on the connection list. |
---|
241 | */ |
---|
242 | if (cs == lastcs) |
---|
243 | comp->last_cs = lcs; |
---|
244 | else { |
---|
245 | lcs->cs_next = cs->cs_next; |
---|
246 | cs->cs_next = lastcs->cs_next; |
---|
247 | lastcs->cs_next = cs; |
---|
248 | } |
---|
249 | } |
---|
250 | |
---|
251 | /* |
---|
252 | * Make sure that only what we expect to change changed. The first |
---|
253 | * line of the `if' checks the IP protocol version, header length & |
---|
254 | * type of service. The 2nd line checks the "Don't fragment" bit. |
---|
255 | * The 3rd line checks the time-to-live and protocol (the protocol |
---|
256 | * check is unnecessary but costless). The 4th line checks the TCP |
---|
257 | * header length. The 5th line checks IP options, if any. The 6th |
---|
258 | * line checks TCP options, if any. If any of these things are |
---|
259 | * different between the previous & current datagram, we send the |
---|
260 | * current datagram `uncompressed'. |
---|
261 | */ |
---|
262 | oth = (struct tcphdr *)&((int32_t *)&cs->cs_ip)[hlen]; |
---|
263 | deltaS = hlen; |
---|
264 | hlen += th->th_off; |
---|
265 | hlen <<= 2; |
---|
266 | if (hlen > m->m_len) |
---|
267 | return TYPE_IP; |
---|
268 | |
---|
269 | if (((u_int16_t *)ip)[0] != ((u_int16_t *)&cs->cs_ip)[0] || |
---|
270 | ((u_int16_t *)ip)[3] != ((u_int16_t *)&cs->cs_ip)[3] || |
---|
271 | ((u_int16_t *)ip)[4] != ((u_int16_t *)&cs->cs_ip)[4] || |
---|
272 | th->th_off != oth->th_off || |
---|
273 | (deltaS > 5 && |
---|
274 | BCMP(ip + 1, &cs->cs_ip + 1, (deltaS - 5) << 2)) || |
---|
275 | (th->th_off > 5 && |
---|
276 | BCMP(th + 1, oth + 1, (th->th_off - 5) << 2))) |
---|
277 | goto uncompressed; |
---|
278 | |
---|
279 | /* |
---|
280 | * Figure out which of the changing fields changed. The |
---|
281 | * receiver expects changes in the order: urgent, window, |
---|
282 | * ack, seq (the order minimizes the number of temporaries |
---|
283 | * needed in this section of code). |
---|
284 | */ |
---|
285 | if (th->th_flags & TH_URG) { |
---|
286 | deltaS = ntohs(th->th_urp); |
---|
287 | ENCODEZ(deltaS); |
---|
288 | changes |= NEW_U; |
---|
289 | } else if (th->th_urp != oth->th_urp) |
---|
290 | /* argh! URG not set but urp changed -- a sensible |
---|
291 | * implementation should never do this but RFC793 |
---|
292 | * doesn't prohibit the change so we have to deal |
---|
293 | * with it. */ |
---|
294 | goto uncompressed; |
---|
295 | |
---|
296 | deltaS = (u_int16_t)(ntohs(th->th_win) - ntohs(oth->th_win)); |
---|
297 | if (deltaS) { |
---|
298 | ENCODE(deltaS); |
---|
299 | changes |= NEW_W; |
---|
300 | } |
---|
301 | |
---|
302 | deltaA = ntohl(th->th_ack) - ntohl(oth->th_ack); |
---|
303 | if (deltaA) { |
---|
304 | if (deltaA > 0xffff) |
---|
305 | goto uncompressed; |
---|
306 | ENCODE(deltaA); |
---|
307 | changes |= NEW_A; |
---|
308 | } |
---|
309 | |
---|
310 | deltaS = ntohl(th->th_seq) - ntohl(oth->th_seq); |
---|
311 | if (deltaS) { |
---|
312 | if (deltaS > 0xffff) |
---|
313 | goto uncompressed; |
---|
314 | ENCODE(deltaS); |
---|
315 | changes |= NEW_S; |
---|
316 | } |
---|
317 | |
---|
318 | switch(changes) { |
---|
319 | |
---|
320 | case 0: |
---|
321 | /* |
---|
322 | * Nothing changed. If this packet contains data and the |
---|
323 | * last one didn't, this is probably a data packet following |
---|
324 | * an ack (normal on an interactive connection) and we send |
---|
325 | * it compressed. Otherwise it's probably a retransmit, |
---|
326 | * retransmitted ack or window probe. Send it uncompressed |
---|
327 | * in case the other side missed the compressed version. |
---|
328 | */ |
---|
329 | if (ip->ip_len != cs->cs_ip.ip_len && |
---|
330 | ntohs(cs->cs_ip.ip_len) == hlen) |
---|
331 | break; |
---|
332 | |
---|
333 | /* FALLTHROUGH */ |
---|
334 | |
---|
335 | case SPECIAL_I: |
---|
336 | case SPECIAL_D: |
---|
337 | /* |
---|
338 | * actual changes match one of our special case encodings -- |
---|
339 | * send packet uncompressed. |
---|
340 | */ |
---|
341 | goto uncompressed; |
---|
342 | |
---|
343 | case NEW_S|NEW_A: |
---|
344 | if (deltaS == deltaA && |
---|
345 | deltaS == ntohs(cs->cs_ip.ip_len) - hlen) { |
---|
346 | /* special case for echoed terminal traffic */ |
---|
347 | changes = SPECIAL_I; |
---|
348 | cp = new_seq; |
---|
349 | } |
---|
350 | break; |
---|
351 | |
---|
352 | case NEW_S: |
---|
353 | if (deltaS == ntohs(cs->cs_ip.ip_len) - hlen) { |
---|
354 | /* special case for data xfer */ |
---|
355 | changes = SPECIAL_D; |
---|
356 | cp = new_seq; |
---|
357 | } |
---|
358 | break; |
---|
359 | } |
---|
360 | |
---|
361 | deltaS = ntohs(ip->ip_id) - ntohs(cs->cs_ip.ip_id); |
---|
362 | if (deltaS != 1) { |
---|
363 | ENCODEZ(deltaS); |
---|
364 | changes |= NEW_I; |
---|
365 | } |
---|
366 | if (th->th_flags & TH_PUSH) |
---|
367 | changes |= TCP_PUSH_BIT; |
---|
368 | /* |
---|
369 | * Grab the cksum before we overwrite it below. Then update our |
---|
370 | * state with this packet's header. |
---|
371 | */ |
---|
372 | deltaA = ntohs(th->th_sum); |
---|
373 | BCOPY(ip, &cs->cs_ip, hlen); |
---|
374 | |
---|
375 | /* |
---|
376 | * We want to use the original packet as our compressed packet. |
---|
377 | * (cp - new_seq) is the number of bytes we need for compressed |
---|
378 | * sequence numbers. In addition we need one byte for the change |
---|
379 | * mask, one for the connection id and two for the tcp checksum. |
---|
380 | * So, (cp - new_seq) + 4 bytes of header are needed. hlen is how |
---|
381 | * many bytes of the original packet to toss so subtract the two to |
---|
382 | * get the new packet size. |
---|
383 | */ |
---|
384 | deltaS = cp - new_seq; |
---|
385 | cp = (u_char *)ip; |
---|
386 | if (compress_cid == 0 || comp->last_xmit != cs->cs_id) { |
---|
387 | comp->last_xmit = cs->cs_id; |
---|
388 | hlen -= deltaS + 4; |
---|
389 | cp += hlen; |
---|
390 | *cp++ = changes | NEW_C; |
---|
391 | *cp++ = cs->cs_id; |
---|
392 | } else { |
---|
393 | hlen -= deltaS + 3; |
---|
394 | cp += hlen; |
---|
395 | *cp++ = changes; |
---|
396 | } |
---|
397 | m->m_len -= hlen; |
---|
398 | m->m_data += hlen; |
---|
399 | *cp++ = deltaA >> 8; |
---|
400 | *cp++ = deltaA; |
---|
401 | BCOPY(new_seq, cp, deltaS); |
---|
402 | INCR(sls_compressed) |
---|
403 | return (TYPE_COMPRESSED_TCP); |
---|
404 | |
---|
405 | /* |
---|
406 | * Update connection state cs & send uncompressed packet ('uncompressed' |
---|
407 | * means a regular ip/tcp packet but with the 'conversation id' we hope |
---|
408 | * to use on future compressed packets in the protocol field). |
---|
409 | */ |
---|
410 | uncompressed: |
---|
411 | BCOPY(ip, &cs->cs_ip, hlen); |
---|
412 | ip->ip_p = cs->cs_id; |
---|
413 | comp->last_xmit = cs->cs_id; |
---|
414 | return (TYPE_UNCOMPRESSED_TCP); |
---|
415 | } |
---|
416 | |
---|
417 | |
---|
418 | int |
---|
419 | sl_uncompress_tcp(bufp, len, type, comp) |
---|
420 | u_char **bufp; |
---|
421 | int len; |
---|
422 | u_int type; |
---|
423 | struct slcompress *comp; |
---|
424 | { |
---|
425 | u_char *hdr, *cp; |
---|
426 | int hlen, vjlen; |
---|
427 | |
---|
428 | cp = bufp? *bufp: NULL; |
---|
429 | vjlen = sl_uncompress_tcp_core(cp, len, len, type, comp, &hdr, &hlen); |
---|
430 | if (vjlen < 0) |
---|
431 | return (0); /* error */ |
---|
432 | if (vjlen == 0) |
---|
433 | return (len); /* was uncompressed already */ |
---|
434 | |
---|
435 | cp += vjlen; |
---|
436 | len -= vjlen; |
---|
437 | |
---|
438 | /* |
---|
439 | * At this point, cp points to the first byte of data in the |
---|
440 | * packet. If we're not aligned on a 4-byte boundary, copy the |
---|
441 | * data down so the ip & tcp headers will be aligned. Then back up |
---|
442 | * cp by the tcp/ip header length to make room for the reconstructed |
---|
443 | * header (we assume the packet we were handed has enough space to |
---|
444 | * prepend 128 bytes of header). |
---|
445 | */ |
---|
446 | if ((intptr_t)cp & 3) { |
---|
447 | if (len > 0) |
---|
448 | BCOPY(cp, ((intptr_t)cp &~ 3), len); |
---|
449 | cp = (u_char *)((intptr_t)cp &~ 3); |
---|
450 | } |
---|
451 | cp -= hlen; |
---|
452 | len += hlen; |
---|
453 | BCOPY(hdr, cp, hlen); |
---|
454 | |
---|
455 | *bufp = cp; |
---|
456 | return (len); |
---|
457 | } |
---|
458 | |
---|
459 | /* |
---|
460 | * Uncompress a packet of total length total_len. The first buflen |
---|
461 | * bytes are at buf; this must include the entire (compressed or |
---|
462 | * uncompressed) TCP/IP header. This procedure returns the length |
---|
463 | * of the VJ header, with a pointer to the uncompressed IP header |
---|
464 | * in *hdrp and its length in *hlenp. |
---|
465 | */ |
---|
466 | int |
---|
467 | sl_uncompress_tcp_core(buf, buflen, total_len, type, comp, hdrp, hlenp) |
---|
468 | u_char *buf; |
---|
469 | int buflen, total_len; |
---|
470 | u_int type; |
---|
471 | struct slcompress *comp; |
---|
472 | u_char **hdrp; |
---|
473 | u_int *hlenp; |
---|
474 | { |
---|
475 | register u_char *cp; |
---|
476 | register u_int hlen, changes; |
---|
477 | register struct tcphdr *th; |
---|
478 | register struct cstate *cs; |
---|
479 | register struct ip *ip; |
---|
480 | register u_int16_t *bp; |
---|
481 | register u_int vjlen; |
---|
482 | |
---|
483 | switch (type) { |
---|
484 | |
---|
485 | case TYPE_UNCOMPRESSED_TCP: |
---|
486 | ip = (struct ip *) buf; |
---|
487 | if (ip->ip_p >= MAX_STATES) |
---|
488 | goto bad; |
---|
489 | cs = &comp->rstate[comp->last_recv = ip->ip_p]; |
---|
490 | comp->flags &=~ SLF_TOSS; |
---|
491 | ip->ip_p = IPPROTO_TCP; |
---|
492 | /* |
---|
493 | * Calculate the size of the TCP/IP header and make sure that |
---|
494 | * we don't overflow the space we have available for it. |
---|
495 | */ |
---|
496 | hlen = ip->ip_hl << 2; |
---|
497 | if (hlen + sizeof(struct tcphdr) > buflen) |
---|
498 | goto bad; |
---|
499 | hlen += ((struct tcphdr *)&((char *)ip)[hlen])->th_off << 2; |
---|
500 | if (hlen > MAX_HDR || hlen > buflen) |
---|
501 | goto bad; |
---|
502 | BCOPY(ip, &cs->cs_ip, hlen); |
---|
503 | cs->cs_hlen = hlen; |
---|
504 | INCR(sls_uncompressedin) |
---|
505 | *hdrp = (u_char *) &cs->cs_ip; |
---|
506 | *hlenp = hlen; |
---|
507 | return (0); |
---|
508 | |
---|
509 | default: |
---|
510 | goto bad; |
---|
511 | |
---|
512 | case TYPE_COMPRESSED_TCP: |
---|
513 | break; |
---|
514 | } |
---|
515 | /* We've got a compressed packet. */ |
---|
516 | INCR(sls_compressedin) |
---|
517 | cp = buf; |
---|
518 | changes = *cp++; |
---|
519 | if (changes & NEW_C) { |
---|
520 | /* Make sure the state index is in range, then grab the state. |
---|
521 | * If we have a good state index, clear the 'discard' flag. */ |
---|
522 | if (*cp >= MAX_STATES) |
---|
523 | goto bad; |
---|
524 | |
---|
525 | comp->flags &=~ SLF_TOSS; |
---|
526 | comp->last_recv = *cp++; |
---|
527 | } else { |
---|
528 | /* this packet has an implicit state index. If we've |
---|
529 | * had a line error since the last time we got an |
---|
530 | * explicit state index, we have to toss the packet. */ |
---|
531 | if (comp->flags & SLF_TOSS) { |
---|
532 | INCR(sls_tossed) |
---|
533 | return (-1); |
---|
534 | } |
---|
535 | } |
---|
536 | cs = &comp->rstate[comp->last_recv]; |
---|
537 | hlen = cs->cs_ip.ip_hl << 2; |
---|
538 | th = (struct tcphdr *)&((u_char *)&cs->cs_ip)[hlen]; |
---|
539 | th->th_sum = htons((*cp << 8) | cp[1]); |
---|
540 | cp += 2; |
---|
541 | if (changes & TCP_PUSH_BIT) |
---|
542 | th->th_flags |= TH_PUSH; |
---|
543 | else |
---|
544 | th->th_flags &=~ TH_PUSH; |
---|
545 | |
---|
546 | switch (changes & SPECIALS_MASK) { |
---|
547 | case SPECIAL_I: |
---|
548 | { |
---|
549 | register u_int i = ntohs(cs->cs_ip.ip_len) - cs->cs_hlen; |
---|
550 | th->th_ack = htonl(ntohl(th->th_ack) + i); |
---|
551 | th->th_seq = htonl(ntohl(th->th_seq) + i); |
---|
552 | } |
---|
553 | break; |
---|
554 | |
---|
555 | case SPECIAL_D: |
---|
556 | th->th_seq = htonl(ntohl(th->th_seq) + ntohs(cs->cs_ip.ip_len) |
---|
557 | - cs->cs_hlen); |
---|
558 | break; |
---|
559 | |
---|
560 | default: |
---|
561 | if (changes & NEW_U) { |
---|
562 | th->th_flags |= TH_URG; |
---|
563 | DECODEU(th->th_urp) |
---|
564 | } else |
---|
565 | th->th_flags &=~ TH_URG; |
---|
566 | if (changes & NEW_W) |
---|
567 | DECODES(th->th_win) |
---|
568 | if (changes & NEW_A) |
---|
569 | DECODEL(th->th_ack) |
---|
570 | if (changes & NEW_S) |
---|
571 | DECODEL(th->th_seq) |
---|
572 | break; |
---|
573 | } |
---|
574 | if (changes & NEW_I) { |
---|
575 | DECODES(cs->cs_ip.ip_id) |
---|
576 | } else |
---|
577 | cs->cs_ip.ip_id = htons(ntohs(cs->cs_ip.ip_id) + 1); |
---|
578 | |
---|
579 | /* |
---|
580 | * At this point, cp points to the first byte of data in the |
---|
581 | * packet. Fill in the IP total length and update the IP |
---|
582 | * header checksum. |
---|
583 | */ |
---|
584 | vjlen = cp - buf; |
---|
585 | buflen -= vjlen; |
---|
586 | if (buflen < 0) |
---|
587 | /* we must have dropped some characters (crc should detect |
---|
588 | * this but the old slip framing won't) */ |
---|
589 | goto bad; |
---|
590 | |
---|
591 | total_len += cs->cs_hlen - vjlen; |
---|
592 | cs->cs_ip.ip_len = htons(total_len); |
---|
593 | |
---|
594 | /* recompute the ip header checksum */ |
---|
595 | bp = (u_int16_t *) &cs->cs_ip; |
---|
596 | cs->cs_ip.ip_sum = 0; |
---|
597 | for (changes = 0; hlen > 0; hlen -= 2) |
---|
598 | changes += *bp++; |
---|
599 | changes = (changes & 0xffff) + (changes >> 16); |
---|
600 | changes = (changes & 0xffff) + (changes >> 16); |
---|
601 | cs->cs_ip.ip_sum = ~ changes; |
---|
602 | |
---|
603 | *hdrp = (u_char *) &cs->cs_ip; |
---|
604 | *hlenp = cs->cs_hlen; |
---|
605 | return vjlen; |
---|
606 | |
---|
607 | bad: |
---|
608 | comp->flags |= SLF_TOSS; |
---|
609 | INCR(sls_errorin) |
---|
610 | return (-1); |
---|
611 | } |
---|