131921Sbrian/*- 231921Sbrian * Copyright (c) 1997 Brian Somers <brian@Awfulhak.org> 331921Sbrian * All rights reserved. 431921Sbrian * 531921Sbrian * Redistribution and use in source and binary forms, with or without 631921Sbrian * modification, are permitted provided that the following conditions 731921Sbrian * are met: 831921Sbrian * 1. Redistributions of source code must retain the above copyright 931921Sbrian * notice, this list of conditions and the following disclaimer. 1031921Sbrian * 2. Redistributions in binary form must reproduce the above copyright 1131921Sbrian * notice, this list of conditions and the following disclaimer in the 1231921Sbrian * documentation and/or other materials provided with the distribution. 1331921Sbrian * 1431921Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1531921Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1631921Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1731921Sbrian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1831921Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1931921Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2031921Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2131921Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2231921Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2331921Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2431921Sbrian * SUCH DAMAGE. 2531921Sbrian * 2650479Speter * $FreeBSD: releng/11.0/usr.sbin/ppp/deflate.c 134789 2004-09-05 01:46:52Z brian $ 2731514Sbrian */ 2831514Sbrian 2936285Sbrian#include <sys/types.h> 3031514Sbrian 3131514Sbrian#include <stdio.h> 3231514Sbrian#include <stdlib.h> 3331514Sbrian#include <zlib.h> 3431514Sbrian 3531514Sbrian#include "mbuf.h" 3631514Sbrian#include "log.h" 3736285Sbrian#include "timer.h" 3836285Sbrian#include "fsm.h" 3931514Sbrian#include "ccp.h" 4031514Sbrian#include "deflate.h" 4131514Sbrian 4231514Sbrian/* Our state */ 4331514Sbrianstruct deflate_state { 4431514Sbrian u_short seqno; 4532381Sbrian int uncomp_rec; 4636285Sbrian int winsize; 4731514Sbrian z_stream cx; 4831514Sbrian}; 4931514Sbrian 5031514Sbrianstatic char garbage[10]; 5131514Sbrianstatic u_char EMPTY_BLOCK[4] = { 0x00, 0x00, 0xff, 0xff }; 5231514Sbrian 5354913Sbrian#define DEFLATE_CHUNK_LEN (1536 - sizeof(struct mbuf)) 5431514Sbrian 5578411Sbrianstatic int 5636285SbrianDeflateResetOutput(void *v) 5731514Sbrian{ 5836285Sbrian struct deflate_state *state = (struct deflate_state *)v; 5936285Sbrian 6036285Sbrian state->seqno = 0; 6136285Sbrian state->uncomp_rec = 0; 6236285Sbrian deflateReset(&state->cx); 6336285Sbrian log_Printf(LogCCP, "Deflate: Output channel reset\n"); 6478411Sbrian 6578411Sbrian return 1; /* Ask FSM to ACK */ 6631514Sbrian} 6731514Sbrian 6846686Sbrianstatic struct mbuf * 69134789SbrianDeflateOutput(void *v, struct ccp *ccp, struct link *l __unused, 70134789Sbrian int pri __unused, u_short *proto, struct mbuf *mp) 7131514Sbrian{ 7236285Sbrian struct deflate_state *state = (struct deflate_state *)v; 7331514Sbrian u_char *wp, *rp; 7431514Sbrian int olen, ilen, len, res, flush; 7531514Sbrian struct mbuf *mo_head, *mo, *mi_head, *mi; 7631514Sbrian 7754912Sbrian ilen = m_length(mp); 7846686Sbrian log_Printf(LogDEBUG, "DeflateOutput: Proto %02x (%d bytes)\n", *proto, ilen); 7936285Sbrian log_DumpBp(LogDEBUG, "DeflateOutput: Compress packet:", mp); 8031514Sbrian 8131514Sbrian /* Stuff the protocol in front of the input */ 8254912Sbrian mi_head = mi = m_get(2, MB_CCPOUT); 8354912Sbrian mi->m_next = mp; 8431514Sbrian rp = MBUF_CTOP(mi); 8546686Sbrian if (*proto < 0x100) { /* Compress the protocol */ 8646686Sbrian rp[0] = *proto & 0377; 8754912Sbrian mi->m_len = 1; 8831514Sbrian } else { /* Don't compress the protocol */ 8946686Sbrian rp[0] = *proto >> 8; 9046686Sbrian rp[1] = *proto & 0377; 9154912Sbrian mi->m_len = 2; 9231514Sbrian } 9331514Sbrian 9431514Sbrian /* Allocate the initial output mbuf */ 9554912Sbrian mo_head = mo = m_get(DEFLATE_CHUNK_LEN, MB_CCPOUT); 9654912Sbrian mo->m_len = 2; 9731514Sbrian wp = MBUF_CTOP(mo); 9836285Sbrian *wp++ = state->seqno >> 8; 9936285Sbrian *wp++ = state->seqno & 0377; 10036285Sbrian log_Printf(LogDEBUG, "DeflateOutput: Seq %d\n", state->seqno); 10136285Sbrian state->seqno++; 10231514Sbrian 10331514Sbrian /* Set up the deflation context */ 10436285Sbrian state->cx.next_out = wp; 10536285Sbrian state->cx.avail_out = DEFLATE_CHUNK_LEN - 2; 10636285Sbrian state->cx.next_in = MBUF_CTOP(mi); 10754912Sbrian state->cx.avail_in = mi->m_len; 10831514Sbrian flush = Z_NO_FLUSH; 10931514Sbrian 11031514Sbrian olen = 0; 11131514Sbrian while (1) { 11236285Sbrian if ((res = deflate(&state->cx, flush)) != Z_OK) { 11331514Sbrian if (res == Z_STREAM_END) 11431514Sbrian break; /* Done */ 11537019Sbrian log_Printf(LogWARN, "DeflateOutput: deflate returned %d (%s)\n", 11636285Sbrian res, state->cx.msg ? state->cx.msg : ""); 11754912Sbrian m_freem(mo_head); 11854912Sbrian m_free(mi_head); 11936285Sbrian state->seqno--; 12046686Sbrian return mp; /* Our dictionary's probably dead now :-( */ 12131514Sbrian } 12231514Sbrian 12336285Sbrian if (flush == Z_SYNC_FLUSH && state->cx.avail_out != 0) 12431514Sbrian break; 12531514Sbrian 12654912Sbrian if (state->cx.avail_in == 0 && mi->m_next != NULL) { 12754912Sbrian mi = mi->m_next; 12836285Sbrian state->cx.next_in = MBUF_CTOP(mi); 12954912Sbrian state->cx.avail_in = mi->m_len; 13054912Sbrian if (mi->m_next == NULL) 13131514Sbrian flush = Z_SYNC_FLUSH; 13231514Sbrian } 13331514Sbrian 13436285Sbrian if (state->cx.avail_out == 0) { 13554912Sbrian mo->m_next = m_get(DEFLATE_CHUNK_LEN, MB_CCPOUT); 13654912Sbrian olen += (mo->m_len = DEFLATE_CHUNK_LEN); 13754912Sbrian mo = mo->m_next; 13854912Sbrian mo->m_len = 0; 13936285Sbrian state->cx.next_out = MBUF_CTOP(mo); 14036285Sbrian state->cx.avail_out = DEFLATE_CHUNK_LEN; 14131514Sbrian } 14231514Sbrian } 14331514Sbrian 14454912Sbrian olen += (mo->m_len = DEFLATE_CHUNK_LEN - state->cx.avail_out); 14531514Sbrian olen -= 4; /* exclude the trailing EMPTY_BLOCK */ 14631514Sbrian 14731514Sbrian /* 14831514Sbrian * If the output packet (including seqno and excluding the EMPTY_BLOCK) 14936285Sbrian * got bigger, send the original. 15031514Sbrian */ 15131514Sbrian if (olen >= ilen) { 15254912Sbrian m_freem(mo_head); 15354912Sbrian m_free(mi_head); 15436285Sbrian log_Printf(LogDEBUG, "DeflateOutput: %d => %d: Uncompressible (0x%04x)\n", 15546686Sbrian ilen, olen, *proto); 15636285Sbrian ccp->uncompout += ilen; 15736285Sbrian ccp->compout += ilen; /* We measure this stuff too */ 15846686Sbrian return mp; 15931514Sbrian } 16031514Sbrian 16154912Sbrian m_freem(mi_head); 16231514Sbrian 16331514Sbrian /* 16431514Sbrian * Lose the last four bytes of our output. 16531514Sbrian * XXX: We should probably assert that these are the same as the 16631514Sbrian * contents of EMPTY_BLOCK. 16731514Sbrian */ 16854912Sbrian mo = mo_head; 16954912Sbrian for (len = mo->m_len; len < olen; mo = mo->m_next, len += mo->m_len) 17031514Sbrian ; 17154912Sbrian mo->m_len -= len - olen; 17254912Sbrian if (mo->m_next != NULL) { 17354912Sbrian m_freem(mo->m_next); 17454912Sbrian mo->m_next = NULL; 17531514Sbrian } 17631514Sbrian 17736285Sbrian ccp->uncompout += ilen; 17836285Sbrian ccp->compout += olen; 17931514Sbrian 18036285Sbrian log_Printf(LogDEBUG, "DeflateOutput: %d => %d bytes, proto 0x%04x\n", 18146686Sbrian ilen, olen, *proto); 18231514Sbrian 18346686Sbrian *proto = ccp_Proto(ccp); 18446686Sbrian return mo_head; 18531514Sbrian} 18631514Sbrian 18731514Sbrianstatic void 18836285SbrianDeflateResetInput(void *v) 18931514Sbrian{ 19036285Sbrian struct deflate_state *state = (struct deflate_state *)v; 19136285Sbrian 19236285Sbrian state->seqno = 0; 19336285Sbrian state->uncomp_rec = 0; 19436285Sbrian inflateReset(&state->cx); 19536285Sbrian log_Printf(LogCCP, "Deflate: Input channel reset\n"); 19631514Sbrian} 19731514Sbrian 19831514Sbrianstatic struct mbuf * 19936285SbrianDeflateInput(void *v, struct ccp *ccp, u_short *proto, struct mbuf *mi) 20031514Sbrian{ 20136285Sbrian struct deflate_state *state = (struct deflate_state *)v; 20231514Sbrian struct mbuf *mo, *mo_head, *mi_head; 20331514Sbrian u_char *wp; 20431514Sbrian int ilen, olen; 20531514Sbrian int seq, flush, res, first; 20631514Sbrian u_char hdr[2]; 20731514Sbrian 20836285Sbrian log_DumpBp(LogDEBUG, "DeflateInput: Decompress packet:", mi); 20936285Sbrian mi_head = mi = mbuf_Read(mi, hdr, 2); 21031514Sbrian ilen = 2; 21131514Sbrian 21231514Sbrian /* Check the sequence number. */ 21331514Sbrian seq = (hdr[0] << 8) + hdr[1]; 21436285Sbrian log_Printf(LogDEBUG, "DeflateInput: Seq %d\n", seq); 21536285Sbrian if (seq != state->seqno) { 21636285Sbrian if (seq <= state->uncomp_rec) 21732381Sbrian /* 21832381Sbrian * So the peer's started at zero again - fine ! If we're wrong, 21932381Sbrian * inflate() will fail. This is better than getting into a loop 22032381Sbrian * trying to get a ResetReq to a busy sender. 22132381Sbrian */ 22236285Sbrian state->seqno = seq; 22332038Sbrian else { 22444650Sbrian log_Printf(LogCCP, "DeflateInput: Seq error: Got %d, expected %d\n", 22536285Sbrian seq, state->seqno); 22654912Sbrian m_freem(mi_head); 22736285Sbrian ccp_SendResetReq(&ccp->fsm); 22832038Sbrian return NULL; 22932038Sbrian } 23031514Sbrian } 23136285Sbrian state->seqno++; 23236285Sbrian state->uncomp_rec = 0; 23331514Sbrian 23431514Sbrian /* Allocate an output mbuf */ 23554912Sbrian mo_head = mo = m_get(DEFLATE_CHUNK_LEN, MB_CCPIN); 23631514Sbrian 23731514Sbrian /* Our proto starts with 0 if it's compressed */ 23831514Sbrian wp = MBUF_CTOP(mo); 23931514Sbrian wp[0] = '\0'; 24031514Sbrian 24131514Sbrian /* 24231514Sbrian * We set avail_out to 1 initially so we can look at the first 24331514Sbrian * byte of the output and decide whether we have a compressed 24431514Sbrian * proto field. 24531514Sbrian */ 24636285Sbrian state->cx.next_in = MBUF_CTOP(mi); 24754912Sbrian state->cx.avail_in = mi->m_len; 24836285Sbrian state->cx.next_out = wp + 1; 24936285Sbrian state->cx.avail_out = 1; 25054912Sbrian ilen += mi->m_len; 25131514Sbrian 25254912Sbrian flush = mi->m_next ? Z_NO_FLUSH : Z_SYNC_FLUSH; 25331514Sbrian first = 1; 25431514Sbrian olen = 0; 25531514Sbrian 25631514Sbrian while (1) { 25736285Sbrian if ((res = inflate(&state->cx, flush)) != Z_OK) { 25831514Sbrian if (res == Z_STREAM_END) 25931514Sbrian break; /* Done */ 26044650Sbrian log_Printf(LogCCP, "DeflateInput: inflate returned %d (%s)\n", 26136285Sbrian res, state->cx.msg ? state->cx.msg : ""); 26254912Sbrian m_freem(mo_head); 26354912Sbrian m_freem(mi); 26436285Sbrian ccp_SendResetReq(&ccp->fsm); 26531514Sbrian return NULL; 26631514Sbrian } 26731514Sbrian 26836285Sbrian if (flush == Z_SYNC_FLUSH && state->cx.avail_out != 0) 26931514Sbrian break; 27031514Sbrian 27154912Sbrian if (state->cx.avail_in == 0 && mi && (mi = m_free(mi)) != NULL) { 27231514Sbrian /* underflow */ 27336285Sbrian state->cx.next_in = MBUF_CTOP(mi); 27454912Sbrian ilen += (state->cx.avail_in = mi->m_len); 27554912Sbrian if (mi->m_next == NULL) 27631514Sbrian flush = Z_SYNC_FLUSH; 27731514Sbrian } 27831514Sbrian 27936285Sbrian if (state->cx.avail_out == 0) { 28031514Sbrian /* overflow */ 28131514Sbrian if (first) { 28231514Sbrian if (!(wp[1] & 1)) { 28331514Sbrian /* 2 byte proto, shuffle it back in output */ 28431514Sbrian wp[0] = wp[1]; 28536285Sbrian state->cx.next_out--; 28636285Sbrian state->cx.avail_out = DEFLATE_CHUNK_LEN-1; 28731514Sbrian } else 28836285Sbrian state->cx.avail_out = DEFLATE_CHUNK_LEN-2; 28931514Sbrian first = 0; 29031514Sbrian } else { 29154912Sbrian olen += (mo->m_len = DEFLATE_CHUNK_LEN); 29254912Sbrian mo->m_next = m_get(DEFLATE_CHUNK_LEN, MB_CCPIN); 29354912Sbrian mo = mo->m_next; 29436285Sbrian state->cx.next_out = MBUF_CTOP(mo); 29536285Sbrian state->cx.avail_out = DEFLATE_CHUNK_LEN; 29631514Sbrian } 29734536Sbrian } 29831514Sbrian } 29931514Sbrian 30031514Sbrian if (mi != NULL) 30154912Sbrian m_freem(mi); 30231514Sbrian 30331514Sbrian if (first) { 30444650Sbrian log_Printf(LogCCP, "DeflateInput: Length error\n"); 30554912Sbrian m_freem(mo_head); 30636285Sbrian ccp_SendResetReq(&ccp->fsm); 30731514Sbrian return NULL; 30831514Sbrian } 30931514Sbrian 31054912Sbrian olen += (mo->m_len = DEFLATE_CHUNK_LEN - state->cx.avail_out); 31131514Sbrian 31231514Sbrian *proto = ((u_short)wp[0] << 8) | wp[1]; 31354912Sbrian mo_head->m_offset += 2; 31454912Sbrian mo_head->m_len -= 2; 31531514Sbrian olen -= 2; 31631514Sbrian 31736285Sbrian ccp->compin += ilen; 31836285Sbrian ccp->uncompin += olen; 31931514Sbrian 32036285Sbrian log_Printf(LogDEBUG, "DeflateInput: %d => %d bytes, proto 0x%04x\n", 32131514Sbrian ilen, olen, *proto); 32231514Sbrian 32331514Sbrian /* 32431514Sbrian * Simulate an EMPTY_BLOCK so that our dictionary stays in sync. 32531514Sbrian * The peer will have silently removed this! 32631514Sbrian */ 32736285Sbrian state->cx.next_out = garbage; 32836285Sbrian state->cx.avail_out = sizeof garbage; 32936285Sbrian state->cx.next_in = EMPTY_BLOCK; 33036285Sbrian state->cx.avail_in = sizeof EMPTY_BLOCK; 33136285Sbrian inflate(&state->cx, Z_SYNC_FLUSH); 33231514Sbrian 33331514Sbrian return mo_head; 33431514Sbrian} 33531514Sbrian 33631514Sbrianstatic void 33736285SbrianDeflateDictSetup(void *v, struct ccp *ccp, u_short proto, struct mbuf *mi) 33831514Sbrian{ 33936285Sbrian struct deflate_state *state = (struct deflate_state *)v; 34031632Sbrian int res, flush, expect_error; 34131514Sbrian u_char *rp; 34231514Sbrian struct mbuf *mi_head; 34331514Sbrian short len; 34431514Sbrian 34536285Sbrian log_Printf(LogDEBUG, "DeflateDictSetup: Got seq %d\n", state->seqno); 34631514Sbrian 34731514Sbrian /* 34831514Sbrian * Stuff an ``uncompressed data'' block header followed by the 34931514Sbrian * protocol in front of the input 35031514Sbrian */ 35154912Sbrian mi_head = m_get(7, MB_CCPOUT); 35254912Sbrian mi_head->m_next = mi; 35354912Sbrian len = m_length(mi); 35431514Sbrian mi = mi_head; 35531514Sbrian rp = MBUF_CTOP(mi); 35631514Sbrian if (proto < 0x100) { /* Compress the protocol */ 35731514Sbrian rp[5] = proto & 0377; 35854912Sbrian mi->m_len = 6; 35931514Sbrian len++; 36031514Sbrian } else { /* Don't compress the protocol */ 36131514Sbrian rp[5] = proto >> 8; 36231514Sbrian rp[6] = proto & 0377; 36354912Sbrian mi->m_len = 7; 36431514Sbrian len += 2; 36531514Sbrian } 36631514Sbrian rp[0] = 0x80; /* BITS: 100xxxxx */ 36731514Sbrian rp[1] = len & 0377; /* The length */ 36831514Sbrian rp[2] = len >> 8; 36931514Sbrian rp[3] = (~len) & 0377; /* One's compliment of the length */ 37031514Sbrian rp[4] = (~len) >> 8; 37131514Sbrian 37236285Sbrian state->cx.next_in = rp; 37354912Sbrian state->cx.avail_in = mi->m_len; 37436285Sbrian state->cx.next_out = garbage; 37536285Sbrian state->cx.avail_out = sizeof garbage; 37631514Sbrian flush = Z_NO_FLUSH; 37731632Sbrian expect_error = 0; 37831514Sbrian 37931514Sbrian while (1) { 38036285Sbrian if ((res = inflate(&state->cx, flush)) != Z_OK) { 38131514Sbrian if (res == Z_STREAM_END) 38231514Sbrian break; /* Done */ 38331632Sbrian if (expect_error && res == Z_BUF_ERROR) 38431632Sbrian break; 38544650Sbrian log_Printf(LogCCP, "DeflateDictSetup: inflate returned %d (%s)\n", 38636285Sbrian res, state->cx.msg ? state->cx.msg : ""); 38744650Sbrian log_Printf(LogCCP, "DeflateDictSetup: avail_in %d, avail_out %d\n", 38836285Sbrian state->cx.avail_in, state->cx.avail_out); 38936285Sbrian ccp_SendResetReq(&ccp->fsm); 39054912Sbrian m_free(mi_head); /* lose our allocated ``head'' buf */ 39131514Sbrian return; 39231514Sbrian } 39331514Sbrian 39436285Sbrian if (flush == Z_SYNC_FLUSH && state->cx.avail_out != 0) 39531514Sbrian break; 39631514Sbrian 39754912Sbrian if (state->cx.avail_in == 0 && mi && (mi = mi->m_next) != NULL) { 39831514Sbrian /* underflow */ 39936285Sbrian state->cx.next_in = MBUF_CTOP(mi); 40054912Sbrian state->cx.avail_in = mi->m_len; 40154912Sbrian if (mi->m_next == NULL) 40231514Sbrian flush = Z_SYNC_FLUSH; 40331514Sbrian } 40431514Sbrian 40536285Sbrian if (state->cx.avail_out == 0) { 40636285Sbrian if (state->cx.avail_in == 0) 40731632Sbrian /* 40831632Sbrian * This seems to be a bug in libz ! If inflate() finished 40931632Sbrian * with 0 avail_in and 0 avail_out *and* this is the end of 41031632Sbrian * our input *and* inflate() *has* actually written all the 41131632Sbrian * output it's going to, it *doesn't* return Z_STREAM_END ! 41231632Sbrian * When we subsequently call it with no more input, it gives 41331632Sbrian * us Z_BUF_ERROR :-( It seems pretty safe to ignore this 41431632Sbrian * error (the dictionary seems to stay in sync). In the worst 41531632Sbrian * case, we'll drop the next compressed packet and do a 41631632Sbrian * CcpReset() then. 41731632Sbrian */ 41831632Sbrian expect_error = 1; 41931514Sbrian /* overflow */ 42036285Sbrian state->cx.next_out = garbage; 42136285Sbrian state->cx.avail_out = sizeof garbage; 42231514Sbrian } 42331514Sbrian } 42431514Sbrian 42536285Sbrian ccp->compin += len; 42636285Sbrian ccp->uncompin += len; 42731514Sbrian 42836285Sbrian state->seqno++; 42936285Sbrian state->uncomp_rec++; 43054912Sbrian m_free(mi_head); /* lose our allocated ``head'' buf */ 43131514Sbrian} 43231514Sbrian 43331514Sbrianstatic const char * 43494894SbrianDeflateDispOpts(struct fsm_opt *o) 43531514Sbrian{ 43637010Sbrian static char disp[7]; /* Must be used immediately */ 43731514Sbrian 43831514Sbrian sprintf(disp, "win %d", (o->data[0]>>4) + 8); 43931514Sbrian return disp; 44031514Sbrian} 44131514Sbrian 44231514Sbrianstatic void 443134789SbrianDeflateInitOptsOutput(struct bundle *bundle __unused, struct fsm_opt *o, 44498132Sbrian const struct ccp_config *cfg) 44531514Sbrian{ 44694894Sbrian o->hdr.len = 4; 44736285Sbrian o->data[0] = ((cfg->deflate.out.winsize - 8) << 4) + 8; 44831514Sbrian o->data[1] = '\0'; 44931514Sbrian} 45031514Sbrian 45136285Sbrianstatic int 452134789SbrianDeflateSetOptsOutput(struct bundle *bundle __unused, struct fsm_opt *o, 453134789Sbrian const struct ccp_config *cfg __unused) 45431514Sbrian{ 45594894Sbrian if (o->hdr.len != 4 || (o->data[0] & 15) != 8 || o->data[1] != '\0') 45636285Sbrian return MODE_REJ; 45731518Sbrian 45836285Sbrian if ((o->data[0] >> 4) + 8 > 15) { 45936285Sbrian o->data[0] = ((15 - 8) << 4) + 8; 46036285Sbrian return MODE_NAK; 46136285Sbrian } 46231514Sbrian 46336285Sbrian return MODE_ACK; 46431514Sbrian} 46531514Sbrian 46631514Sbrianstatic int 467134789SbrianDeflateSetOptsInput(struct bundle *bundle __unused, struct fsm_opt *o, 46898132Sbrian const struct ccp_config *cfg) 46931514Sbrian{ 47036285Sbrian int want; 47136285Sbrian 47294894Sbrian if (o->hdr.len != 4 || (o->data[0] & 15) != 8 || o->data[1] != '\0') 47331514Sbrian return MODE_REJ; 47436285Sbrian 47536285Sbrian want = (o->data[0] >> 4) + 8; 47636285Sbrian if (cfg->deflate.in.winsize == 0) { 47736285Sbrian if (want < 8 || want > 15) { 47836285Sbrian o->data[0] = ((15 - 8) << 4) + 8; 47936285Sbrian } 48036285Sbrian } else if (want != cfg->deflate.in.winsize) { 48136285Sbrian o->data[0] = ((cfg->deflate.in.winsize - 8) << 4) + 8; 48231514Sbrian return MODE_NAK; 48331514Sbrian } 48431514Sbrian 48531514Sbrian return MODE_ACK; 48631514Sbrian} 48731514Sbrian 48836285Sbrianstatic void * 489134789SbrianDeflateInitInput(struct bundle *bundle __unused, struct fsm_opt *o) 49031514Sbrian{ 49136285Sbrian struct deflate_state *state; 49231514Sbrian 49336285Sbrian state = (struct deflate_state *)malloc(sizeof(struct deflate_state)); 49436285Sbrian if (state != NULL) { 49536285Sbrian state->winsize = (o->data[0] >> 4) + 8; 49636285Sbrian state->cx.zalloc = NULL; 49736285Sbrian state->cx.opaque = NULL; 49836285Sbrian state->cx.zfree = NULL; 49936285Sbrian state->cx.next_out = NULL; 50036285Sbrian if (inflateInit2(&state->cx, -state->winsize) == Z_OK) 50136285Sbrian DeflateResetInput(state); 50236285Sbrian else { 50336285Sbrian free(state); 50436285Sbrian state = NULL; 50536285Sbrian } 50636285Sbrian } 50731514Sbrian 50836285Sbrian return state; 50931518Sbrian} 51031518Sbrian 51136285Sbrianstatic void * 512134789SbrianDeflateInitOutput(struct bundle *bundle __unused, struct fsm_opt *o) 51331518Sbrian{ 51436285Sbrian struct deflate_state *state; 51531518Sbrian 51636285Sbrian state = (struct deflate_state *)malloc(sizeof(struct deflate_state)); 51736285Sbrian if (state != NULL) { 51836285Sbrian state->winsize = (o->data[0] >> 4) + 8; 51936285Sbrian state->cx.zalloc = NULL; 52036285Sbrian state->cx.opaque = NULL; 52136285Sbrian state->cx.zfree = NULL; 52236285Sbrian state->cx.next_in = NULL; 52336285Sbrian if (deflateInit2(&state->cx, Z_DEFAULT_COMPRESSION, 8, 52436285Sbrian -state->winsize, 8, Z_DEFAULT_STRATEGY) == Z_OK) 52536285Sbrian DeflateResetOutput(state); 52636285Sbrian else { 52736285Sbrian free(state); 52836285Sbrian state = NULL; 52936285Sbrian } 53036285Sbrian } 53131514Sbrian 53236285Sbrian return state; 53331514Sbrian} 53431514Sbrian 53531514Sbrianstatic void 53636285SbrianDeflateTermInput(void *v) 53731514Sbrian{ 53836285Sbrian struct deflate_state *state = (struct deflate_state *)v; 53936285Sbrian 54036285Sbrian inflateEnd(&state->cx); 54136285Sbrian free(state); 54231514Sbrian} 54331514Sbrian 54431514Sbrianstatic void 54536285SbrianDeflateTermOutput(void *v) 54631514Sbrian{ 54736285Sbrian struct deflate_state *state = (struct deflate_state *)v; 54836285Sbrian 54936285Sbrian deflateEnd(&state->cx); 55036285Sbrian free(state); 55131514Sbrian} 55231514Sbrian 55331518Sbrianconst struct ccp_algorithm PppdDeflateAlgorithm = { 55472025Sbrian TY_PPPD_DEFLATE, /* Older versions of pppd expected this ``type'' */ 55536285Sbrian CCP_NEG_DEFLATE24, 55631518Sbrian DeflateDispOpts, 55778411Sbrian ccp_DefaultUsable, 55878411Sbrian ccp_DefaultRequired, 55931518Sbrian { 56036285Sbrian DeflateSetOptsInput, 56131518Sbrian DeflateInitInput, 56231518Sbrian DeflateTermInput, 56331518Sbrian DeflateResetInput, 56431518Sbrian DeflateInput, 56531518Sbrian DeflateDictSetup 56631518Sbrian }, 56731518Sbrian { 56879165Sbrian 0, 56936285Sbrian DeflateInitOptsOutput, 57036285Sbrian DeflateSetOptsOutput, 57131518Sbrian DeflateInitOutput, 57231518Sbrian DeflateTermOutput, 57331518Sbrian DeflateResetOutput, 57431518Sbrian DeflateOutput 57531518Sbrian }, 57631518Sbrian}; 57731518Sbrian 57831514Sbrianconst struct ccp_algorithm DeflateAlgorithm = { 57931518Sbrian TY_DEFLATE, /* rfc 1979 */ 58036285Sbrian CCP_NEG_DEFLATE, 58131514Sbrian DeflateDispOpts, 58278411Sbrian ccp_DefaultUsable, 58378411Sbrian ccp_DefaultRequired, 58431514Sbrian { 58536285Sbrian DeflateSetOptsInput, 58631514Sbrian DeflateInitInput, 58731514Sbrian DeflateTermInput, 58831514Sbrian DeflateResetInput, 58931514Sbrian DeflateInput, 59031514Sbrian DeflateDictSetup 59131514Sbrian }, 59231514Sbrian { 59379165Sbrian 0, 59436285Sbrian DeflateInitOptsOutput, 59536285Sbrian DeflateSetOptsOutput, 59631514Sbrian DeflateInitOutput, 59731514Sbrian DeflateTermOutput, 59831514Sbrian DeflateResetOutput, 59931514Sbrian DeflateOutput 60031514Sbrian }, 60131514Sbrian}; 602