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