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