1 /*- 2 * Copyright (c) 1997 Brian Somers <brian@Awfulhak.org> 3 * 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 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $Id: deflate.c,v 1.8 1998/05/21 21:45:00 brian Exp $ 27 */ 28 29 #include <sys/types.h> 30 31 #include <stdio.h> 32 #include <stdlib.h> 33 #include <zlib.h> 34 35 #include "mbuf.h" 36 #include "log.h" 37 #include "timer.h" 38 #include "lqr.h" 39 #include "hdlc.h" 40 #include "fsm.h" 41 #include "lcp.h" 42 #include "ccp.h" 43 #include "deflate.h" 44 45 /* Our state */ 46 struct deflate_state { 47 u_short seqno; 48 int uncomp_rec; 49 int winsize; 50 z_stream cx; 51 }; 52 53 static char garbage[10]; 54 static u_char EMPTY_BLOCK[4] = { 0x00, 0x00, 0xff, 0xff }; 55 56 #define DEFLATE_CHUNK_LEN 1024 /* Allocate mbufs this size */ 57 58 static void 59 DeflateResetOutput(void *v) 60 { 61 struct deflate_state *state = (struct deflate_state *)v; 62 63 state->seqno = 0; 64 state->uncomp_rec = 0; 65 deflateReset(&state->cx); 66 log_Printf(LogCCP, "Deflate: Output channel reset\n"); 67 } 68 69 static int 70 DeflateOutput(void *v, struct ccp *ccp, struct link *l, int pri, u_short proto, 71 struct mbuf *mp) 72 { 73 struct deflate_state *state = (struct deflate_state *)v; 74 u_char *wp, *rp; 75 int olen, ilen, len, res, flush; 76 struct mbuf *mo_head, *mo, *mi_head, *mi; 77 78 ilen = mbuf_Length(mp); 79 log_Printf(LogDEBUG, "DeflateOutput: Proto %02x (%d bytes)\n", proto, ilen); 80 log_DumpBp(LogDEBUG, "DeflateOutput: Compress packet:", mp); 81 82 /* Stuff the protocol in front of the input */ 83 mi_head = mi = mbuf_Alloc(2, MB_HDLCOUT); 84 mi->next = mp; 85 rp = MBUF_CTOP(mi); 86 if (proto < 0x100) { /* Compress the protocol */ 87 rp[0] = proto & 0377; 88 mi->cnt = 1; 89 } else { /* Don't compress the protocol */ 90 rp[0] = proto >> 8; 91 rp[1] = proto & 0377; 92 mi->cnt = 2; 93 } 94 95 /* Allocate the initial output mbuf */ 96 mo_head = mo = mbuf_Alloc(DEFLATE_CHUNK_LEN, MB_HDLCOUT); 97 mo->cnt = 2; 98 wp = MBUF_CTOP(mo); 99 *wp++ = state->seqno >> 8; 100 *wp++ = state->seqno & 0377; 101 log_Printf(LogDEBUG, "DeflateOutput: Seq %d\n", state->seqno); 102 state->seqno++; 103 104 /* Set up the deflation context */ 105 state->cx.next_out = wp; 106 state->cx.avail_out = DEFLATE_CHUNK_LEN - 2; 107 state->cx.next_in = MBUF_CTOP(mi); 108 state->cx.avail_in = mi->cnt; 109 flush = Z_NO_FLUSH; 110 111 olen = 0; 112 while (1) { 113 if ((res = deflate(&state->cx, flush)) != Z_OK) { 114 if (res == Z_STREAM_END) 115 break; /* Done */ 116 log_Printf(LogERROR, "DeflateOutput: deflate returned %d (%s)\n", 117 res, state->cx.msg ? state->cx.msg : ""); 118 mbuf_Free(mo_head); 119 mbuf_FreeSeg(mi_head); 120 state->seqno--; 121 return 1; /* packet dropped */ 122 } 123 124 if (flush == Z_SYNC_FLUSH && state->cx.avail_out != 0) 125 break; 126 127 if (state->cx.avail_in == 0 && mi->next != NULL) { 128 mi = mi->next; 129 state->cx.next_in = MBUF_CTOP(mi); 130 state->cx.avail_in = mi->cnt; 131 if (mi->next == NULL) 132 flush = Z_SYNC_FLUSH; 133 } 134 135 if (state->cx.avail_out == 0) { 136 mo->next = mbuf_Alloc(DEFLATE_CHUNK_LEN, MB_HDLCOUT); 137 olen += (mo->cnt = DEFLATE_CHUNK_LEN); 138 mo = mo->next; 139 mo->cnt = 0; 140 state->cx.next_out = MBUF_CTOP(mo); 141 state->cx.avail_out = DEFLATE_CHUNK_LEN; 142 } 143 } 144 145 olen += (mo->cnt = DEFLATE_CHUNK_LEN - state->cx.avail_out); 146 olen -= 4; /* exclude the trailing EMPTY_BLOCK */ 147 148 /* 149 * If the output packet (including seqno and excluding the EMPTY_BLOCK) 150 * got bigger, send the original. 151 */ 152 if (olen >= ilen) { 153 mbuf_Free(mo_head); 154 mbuf_FreeSeg(mi_head); 155 log_Printf(LogDEBUG, "DeflateOutput: %d => %d: Uncompressible (0x%04x)\n", 156 ilen, olen, proto); 157 ccp->uncompout += ilen; 158 ccp->compout += ilen; /* We measure this stuff too */ 159 return 0; 160 } 161 162 mbuf_Free(mi_head); 163 164 /* 165 * Lose the last four bytes of our output. 166 * XXX: We should probably assert that these are the same as the 167 * contents of EMPTY_BLOCK. 168 */ 169 for (mo = mo_head, len = mo->cnt; len < olen; mo = mo->next, len += mo->cnt) 170 ; 171 mo->cnt -= len - olen; 172 if (mo->next != NULL) { 173 mbuf_Free(mo->next); 174 mo->next = NULL; 175 } 176 177 ccp->uncompout += ilen; 178 ccp->compout += olen; 179 180 log_Printf(LogDEBUG, "DeflateOutput: %d => %d bytes, proto 0x%04x\n", 181 ilen, olen, proto); 182 183 hdlc_Output(l, PRI_NORMAL, ccp_Proto(ccp), mo_head); 184 return 1; 185 } 186 187 static void 188 DeflateResetInput(void *v) 189 { 190 struct deflate_state *state = (struct deflate_state *)v; 191 192 state->seqno = 0; 193 state->uncomp_rec = 0; 194 inflateReset(&state->cx); 195 log_Printf(LogCCP, "Deflate: Input channel reset\n"); 196 } 197 198 static struct mbuf * 199 DeflateInput(void *v, struct ccp *ccp, u_short *proto, struct mbuf *mi) 200 { 201 struct deflate_state *state = (struct deflate_state *)v; 202 struct mbuf *mo, *mo_head, *mi_head; 203 u_char *wp; 204 int ilen, olen; 205 int seq, flush, res, first; 206 u_char hdr[2]; 207 208 log_DumpBp(LogDEBUG, "DeflateInput: Decompress packet:", mi); 209 mi_head = mi = mbuf_Read(mi, hdr, 2); 210 ilen = 2; 211 212 /* Check the sequence number. */ 213 seq = (hdr[0] << 8) + hdr[1]; 214 log_Printf(LogDEBUG, "DeflateInput: Seq %d\n", seq); 215 if (seq != state->seqno) { 216 if (seq <= state->uncomp_rec) 217 /* 218 * So the peer's started at zero again - fine ! If we're wrong, 219 * inflate() will fail. This is better than getting into a loop 220 * trying to get a ResetReq to a busy sender. 221 */ 222 state->seqno = seq; 223 else { 224 log_Printf(LogERROR, "DeflateInput: Seq error: Got %d, expected %d\n", 225 seq, state->seqno); 226 mbuf_Free(mi_head); 227 ccp_SendResetReq(&ccp->fsm); 228 return NULL; 229 } 230 } 231 state->seqno++; 232 state->uncomp_rec = 0; 233 234 /* Allocate an output mbuf */ 235 mo_head = mo = mbuf_Alloc(DEFLATE_CHUNK_LEN, MB_IPIN); 236 237 /* Our proto starts with 0 if it's compressed */ 238 wp = MBUF_CTOP(mo); 239 wp[0] = '\0'; 240 241 /* 242 * We set avail_out to 1 initially so we can look at the first 243 * byte of the output and decide whether we have a compressed 244 * proto field. 245 */ 246 state->cx.next_in = MBUF_CTOP(mi); 247 state->cx.avail_in = mi->cnt; 248 state->cx.next_out = wp + 1; 249 state->cx.avail_out = 1; 250 ilen += mi->cnt; 251 252 flush = mi->next ? Z_NO_FLUSH : Z_SYNC_FLUSH; 253 first = 1; 254 olen = 0; 255 256 while (1) { 257 if ((res = inflate(&state->cx, flush)) != Z_OK) { 258 if (res == Z_STREAM_END) 259 break; /* Done */ 260 log_Printf(LogERROR, "DeflateInput: inflate returned %d (%s)\n", 261 res, state->cx.msg ? state->cx.msg : ""); 262 mbuf_Free(mo_head); 263 mbuf_Free(mi); 264 ccp_SendResetReq(&ccp->fsm); 265 return NULL; 266 } 267 268 if (flush == Z_SYNC_FLUSH && state->cx.avail_out != 0) 269 break; 270 271 if (state->cx.avail_in == 0 && mi && (mi = mbuf_FreeSeg(mi)) != NULL) { 272 /* underflow */ 273 state->cx.next_in = MBUF_CTOP(mi); 274 ilen += (state->cx.avail_in = mi->cnt); 275 if (mi->next == NULL) 276 flush = Z_SYNC_FLUSH; 277 } 278 279 if (state->cx.avail_out == 0) { 280 /* overflow */ 281 if (first) { 282 if (!(wp[1] & 1)) { 283 /* 2 byte proto, shuffle it back in output */ 284 wp[0] = wp[1]; 285 state->cx.next_out--; 286 state->cx.avail_out = DEFLATE_CHUNK_LEN-1; 287 } else 288 state->cx.avail_out = DEFLATE_CHUNK_LEN-2; 289 first = 0; 290 } else { 291 olen += (mo->cnt = DEFLATE_CHUNK_LEN); 292 mo->next = mbuf_Alloc(DEFLATE_CHUNK_LEN, MB_IPIN); 293 mo = mo->next; 294 state->cx.next_out = MBUF_CTOP(mo); 295 state->cx.avail_out = DEFLATE_CHUNK_LEN; 296 } 297 } 298 } 299 300 if (mi != NULL) 301 mbuf_Free(mi); 302 303 if (first) { 304 log_Printf(LogERROR, "DeflateInput: Length error\n"); 305 mbuf_Free(mo_head); 306 ccp_SendResetReq(&ccp->fsm); 307 return NULL; 308 } 309 310 olen += (mo->cnt = DEFLATE_CHUNK_LEN - state->cx.avail_out); 311 312 *proto = ((u_short)wp[0] << 8) | wp[1]; 313 mo_head->offset += 2; 314 mo_head->cnt -= 2; 315 olen -= 2; 316 317 ccp->compin += ilen; 318 ccp->uncompin += olen; 319 320 log_Printf(LogDEBUG, "DeflateInput: %d => %d bytes, proto 0x%04x\n", 321 ilen, olen, *proto); 322 323 /* 324 * Simulate an EMPTY_BLOCK so that our dictionary stays in sync. 325 * The peer will have silently removed this! 326 */ 327 state->cx.next_out = garbage; 328 state->cx.avail_out = sizeof garbage; 329 state->cx.next_in = EMPTY_BLOCK; 330 state->cx.avail_in = sizeof EMPTY_BLOCK; 331 inflate(&state->cx, Z_SYNC_FLUSH); 332 333 return mo_head; 334 } 335 336 static void 337 DeflateDictSetup(void *v, struct ccp *ccp, u_short proto, struct mbuf *mi) 338 { 339 struct deflate_state *state = (struct deflate_state *)v; 340 int res, flush, expect_error; 341 u_char *rp; 342 struct mbuf *mi_head; 343 short len; 344 345 log_Printf(LogDEBUG, "DeflateDictSetup: Got seq %d\n", state->seqno); 346 347 /* 348 * Stuff an ``uncompressed data'' block header followed by the 349 * protocol in front of the input 350 */ 351 mi_head = mbuf_Alloc(7, MB_HDLCOUT); 352 mi_head->next = mi; 353 len = mbuf_Length(mi); 354 mi = mi_head; 355 rp = MBUF_CTOP(mi); 356 if (proto < 0x100) { /* Compress the protocol */ 357 rp[5] = proto & 0377; 358 mi->cnt = 6; 359 len++; 360 } else { /* Don't compress the protocol */ 361 rp[5] = proto >> 8; 362 rp[6] = proto & 0377; 363 mi->cnt = 7; 364 len += 2; 365 } 366 rp[0] = 0x80; /* BITS: 100xxxxx */ 367 rp[1] = len & 0377; /* The length */ 368 rp[2] = len >> 8; 369 rp[3] = (~len) & 0377; /* One's compliment of the length */ 370 rp[4] = (~len) >> 8; 371 372 state->cx.next_in = rp; 373 state->cx.avail_in = mi->cnt; 374 state->cx.next_out = garbage; 375 state->cx.avail_out = sizeof garbage; 376 flush = Z_NO_FLUSH; 377 expect_error = 0; 378 379 while (1) { 380 if ((res = inflate(&state->cx, flush)) != Z_OK) { 381 if (res == Z_STREAM_END) 382 break; /* Done */ 383 if (expect_error && res == Z_BUF_ERROR) 384 break; 385 log_Printf(LogERROR, "DeflateDictSetup: inflate returned %d (%s)\n", 386 res, state->cx.msg ? state->cx.msg : ""); 387 log_Printf(LogERROR, "DeflateDictSetup: avail_in %d, avail_out %d\n", 388 state->cx.avail_in, state->cx.avail_out); 389 ccp_SendResetReq(&ccp->fsm); 390 mbuf_FreeSeg(mi_head); /* lose our allocated ``head'' buf */ 391 return; 392 } 393 394 if (flush == Z_SYNC_FLUSH && state->cx.avail_out != 0) 395 break; 396 397 if (state->cx.avail_in == 0 && mi && (mi = mi->next) != NULL) { 398 /* underflow */ 399 state->cx.next_in = MBUF_CTOP(mi); 400 state->cx.avail_in = mi->cnt; 401 if (mi->next == NULL) 402 flush = Z_SYNC_FLUSH; 403 } 404 405 if (state->cx.avail_out == 0) { 406 if (state->cx.avail_in == 0) 407 /* 408 * This seems to be a bug in libz ! If inflate() finished 409 * with 0 avail_in and 0 avail_out *and* this is the end of 410 * our input *and* inflate() *has* actually written all the 411 * output it's going to, it *doesn't* return Z_STREAM_END ! 412 * When we subsequently call it with no more input, it gives 413 * us Z_BUF_ERROR :-( It seems pretty safe to ignore this 414 * error (the dictionary seems to stay in sync). In the worst 415 * case, we'll drop the next compressed packet and do a 416 * CcpReset() then. 417 */ 418 expect_error = 1; 419 /* overflow */ 420 state->cx.next_out = garbage; 421 state->cx.avail_out = sizeof garbage; 422 } 423 } 424 425 ccp->compin += len; 426 ccp->uncompin += len; 427 428 state->seqno++; 429 state->uncomp_rec++; 430 mbuf_FreeSeg(mi_head); /* lose our allocated ``head'' buf */ 431 } 432 433 static const char * 434 DeflateDispOpts(struct lcp_opt *o) 435 { 436 static char disp[7]; /* Must be used immediately */ 437 438 sprintf(disp, "win %d", (o->data[0]>>4) + 8); 439 return disp; 440 } 441 442 static void 443 DeflateInitOptsOutput(struct lcp_opt *o, const struct ccp_config *cfg) 444 { 445 o->len = 4; 446 o->data[0] = ((cfg->deflate.out.winsize - 8) << 4) + 8; 447 o->data[1] = '\0'; 448 } 449 450 static int 451 DeflateSetOptsOutput(struct lcp_opt *o) 452 { 453 if (o->len != 4 || (o->data[0] & 15) != 8 || o->data[1] != '\0') 454 return MODE_REJ; 455 456 if ((o->data[0] >> 4) + 8 > 15) { 457 o->data[0] = ((15 - 8) << 4) + 8; 458 return MODE_NAK; 459 } 460 461 return MODE_ACK; 462 } 463 464 static int 465 DeflateSetOptsInput(struct lcp_opt *o, const struct ccp_config *cfg) 466 { 467 int want; 468 469 if (o->len != 4 || (o->data[0] & 15) != 8 || o->data[1] != '\0') 470 return MODE_REJ; 471 472 want = (o->data[0] >> 4) + 8; 473 if (cfg->deflate.in.winsize == 0) { 474 if (want < 8 || want > 15) { 475 o->data[0] = ((15 - 8) << 4) + 8; 476 } 477 } else if (want != cfg->deflate.in.winsize) { 478 o->data[0] = ((cfg->deflate.in.winsize - 8) << 4) + 8; 479 return MODE_NAK; 480 } 481 482 return MODE_ACK; 483 } 484 485 static void * 486 DeflateInitInput(struct lcp_opt *o) 487 { 488 struct deflate_state *state; 489 490 state = (struct deflate_state *)malloc(sizeof(struct deflate_state)); 491 if (state != NULL) { 492 state->winsize = (o->data[0] >> 4) + 8; 493 state->cx.zalloc = NULL; 494 state->cx.opaque = NULL; 495 state->cx.zfree = NULL; 496 state->cx.next_out = NULL; 497 if (inflateInit2(&state->cx, -state->winsize) == Z_OK) 498 DeflateResetInput(state); 499 else { 500 free(state); 501 state = NULL; 502 } 503 } 504 505 return state; 506 } 507 508 static void * 509 DeflateInitOutput(struct lcp_opt *o) 510 { 511 struct deflate_state *state; 512 513 state = (struct deflate_state *)malloc(sizeof(struct deflate_state)); 514 if (state != NULL) { 515 state->winsize = (o->data[0] >> 4) + 8; 516 state->cx.zalloc = NULL; 517 state->cx.opaque = NULL; 518 state->cx.zfree = NULL; 519 state->cx.next_in = NULL; 520 if (deflateInit2(&state->cx, Z_DEFAULT_COMPRESSION, 8, 521 -state->winsize, 8, Z_DEFAULT_STRATEGY) == Z_OK) 522 DeflateResetOutput(state); 523 else { 524 free(state); 525 state = NULL; 526 } 527 } 528 529 return state; 530 } 531 532 static void 533 DeflateTermInput(void *v) 534 { 535 struct deflate_state *state = (struct deflate_state *)v; 536 537 inflateEnd(&state->cx); 538 free(state); 539 } 540 541 static void 542 DeflateTermOutput(void *v) 543 { 544 struct deflate_state *state = (struct deflate_state *)v; 545 546 deflateEnd(&state->cx); 547 free(state); 548 } 549 550 const struct ccp_algorithm PppdDeflateAlgorithm = { 551 TY_PPPD_DEFLATE, /* pppd (wrongly) expects this ``type'' field */ 552 CCP_NEG_DEFLATE24, 553 DeflateDispOpts, 554 { 555 DeflateSetOptsInput, 556 DeflateInitInput, 557 DeflateTermInput, 558 DeflateResetInput, 559 DeflateInput, 560 DeflateDictSetup 561 }, 562 { 563 DeflateInitOptsOutput, 564 DeflateSetOptsOutput, 565 DeflateInitOutput, 566 DeflateTermOutput, 567 DeflateResetOutput, 568 DeflateOutput 569 }, 570 }; 571 572 const struct ccp_algorithm DeflateAlgorithm = { 573 TY_DEFLATE, /* rfc 1979 */ 574 CCP_NEG_DEFLATE, 575 DeflateDispOpts, 576 { 577 DeflateSetOptsInput, 578 DeflateInitInput, 579 DeflateTermInput, 580 DeflateResetInput, 581 DeflateInput, 582 DeflateDictSetup 583 }, 584 { 585 DeflateInitOptsOutput, 586 DeflateSetOptsOutput, 587 DeflateInitOutput, 588 DeflateTermOutput, 589 DeflateResetOutput, 590 DeflateOutput 591 }, 592 }; 593