1c39934eaSBrian Somers /*-
2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
31de7b4b8SPedro F. Giffuni *
4c39934eaSBrian Somers * Copyright (c) 1997 Brian Somers <brian@Awfulhak.org>
5c39934eaSBrian Somers * All rights reserved.
6c39934eaSBrian Somers *
7c39934eaSBrian Somers * Redistribution and use in source and binary forms, with or without
8c39934eaSBrian Somers * modification, are permitted provided that the following conditions
9c39934eaSBrian Somers * are met:
10c39934eaSBrian Somers * 1. Redistributions of source code must retain the above copyright
11c39934eaSBrian Somers * notice, this list of conditions and the following disclaimer.
12c39934eaSBrian Somers * 2. Redistributions in binary form must reproduce the above copyright
13c39934eaSBrian Somers * notice, this list of conditions and the following disclaimer in the
14c39934eaSBrian Somers * documentation and/or other materials provided with the distribution.
15c39934eaSBrian Somers *
16c39934eaSBrian Somers * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17c39934eaSBrian Somers * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18c39934eaSBrian Somers * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19c39934eaSBrian Somers * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20c39934eaSBrian Somers * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21c39934eaSBrian Somers * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22c39934eaSBrian Somers * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23c39934eaSBrian Somers * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24c39934eaSBrian Somers * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25c39934eaSBrian Somers * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26c39934eaSBrian Somers * SUCH DAMAGE.
270053cc58SBrian Somers */
280053cc58SBrian Somers
292764b86aSBrian Somers #include <sys/types.h>
300053cc58SBrian Somers
310053cc58SBrian Somers #include <stdio.h>
320053cc58SBrian Somers #include <stdlib.h>
330053cc58SBrian Somers #include <zlib.h>
340053cc58SBrian Somers
350053cc58SBrian Somers #include "mbuf.h"
360053cc58SBrian Somers #include "log.h"
37c8ee0d78SBrian Somers #include "timer.h"
387308ec68SBrian Somers #include "fsm.h"
390053cc58SBrian Somers #include "ccp.h"
400053cc58SBrian Somers #include "deflate.h"
410053cc58SBrian Somers
420053cc58SBrian Somers /* Our state */
430053cc58SBrian Somers struct deflate_state {
440053cc58SBrian Somers u_short seqno;
4598baf7c8SBrian Somers int uncomp_rec;
4603036ec7SBrian Somers int winsize;
470053cc58SBrian Somers z_stream cx;
480053cc58SBrian Somers };
490053cc58SBrian Somers
500053cc58SBrian Somers static char garbage[10];
510053cc58SBrian Somers static u_char EMPTY_BLOCK[4] = { 0x00, 0x00, 0xff, 0xff };
520053cc58SBrian Somers
53dae8dd31SBrian Somers #define DEFLATE_CHUNK_LEN (1536 - sizeof(struct mbuf))
540053cc58SBrian Somers
556cf6ee76SBrian Somers static int
DeflateResetOutput(void * v)5603036ec7SBrian Somers DeflateResetOutput(void *v)
570053cc58SBrian Somers {
5803036ec7SBrian Somers struct deflate_state *state = (struct deflate_state *)v;
5903036ec7SBrian Somers
6003036ec7SBrian Somers state->seqno = 0;
6103036ec7SBrian Somers state->uncomp_rec = 0;
6203036ec7SBrian Somers deflateReset(&state->cx);
63dd7e2610SBrian Somers log_Printf(LogCCP, "Deflate: Output channel reset\n");
646cf6ee76SBrian Somers
656cf6ee76SBrian Somers return 1; /* Ask FSM to ACK */
660053cc58SBrian Somers }
670053cc58SBrian Somers
685d9e6103SBrian Somers static struct mbuf *
DeflateOutput(void * v,struct ccp * ccp,struct link * l __unused,int pri __unused,u_short * proto,struct mbuf * mp)69057f1760SBrian Somers DeflateOutput(void *v, struct ccp *ccp, struct link *l __unused,
70057f1760SBrian Somers int pri __unused, u_short *proto, struct mbuf *mp)
710053cc58SBrian Somers {
7203036ec7SBrian Somers struct deflate_state *state = (struct deflate_state *)v;
730053cc58SBrian Somers u_char *wp, *rp;
740053cc58SBrian Somers int olen, ilen, len, res, flush;
750053cc58SBrian Somers struct mbuf *mo_head, *mo, *mi_head, *mi;
760053cc58SBrian Somers
7726af0ae9SBrian Somers ilen = m_length(mp);
785d9e6103SBrian Somers log_Printf(LogDEBUG, "DeflateOutput: Proto %02x (%d bytes)\n", *proto, ilen);
79dd7e2610SBrian Somers log_DumpBp(LogDEBUG, "DeflateOutput: Compress packet:", mp);
800053cc58SBrian Somers
810053cc58SBrian Somers /* Stuff the protocol in front of the input */
8226af0ae9SBrian Somers mi_head = mi = m_get(2, MB_CCPOUT);
8326af0ae9SBrian Somers mi->m_next = mp;
840053cc58SBrian Somers rp = MBUF_CTOP(mi);
855d9e6103SBrian Somers if (*proto < 0x100) { /* Compress the protocol */
865d9e6103SBrian Somers rp[0] = *proto & 0377;
8726af0ae9SBrian Somers mi->m_len = 1;
880053cc58SBrian Somers } else { /* Don't compress the protocol */
895d9e6103SBrian Somers rp[0] = *proto >> 8;
905d9e6103SBrian Somers rp[1] = *proto & 0377;
9126af0ae9SBrian Somers mi->m_len = 2;
920053cc58SBrian Somers }
930053cc58SBrian Somers
940053cc58SBrian Somers /* Allocate the initial output mbuf */
9526af0ae9SBrian Somers mo_head = mo = m_get(DEFLATE_CHUNK_LEN, MB_CCPOUT);
9626af0ae9SBrian Somers mo->m_len = 2;
970053cc58SBrian Somers wp = MBUF_CTOP(mo);
9803036ec7SBrian Somers *wp++ = state->seqno >> 8;
9903036ec7SBrian Somers *wp++ = state->seqno & 0377;
100dd7e2610SBrian Somers log_Printf(LogDEBUG, "DeflateOutput: Seq %d\n", state->seqno);
10103036ec7SBrian Somers state->seqno++;
1020053cc58SBrian Somers
1030053cc58SBrian Somers /* Set up the deflation context */
10403036ec7SBrian Somers state->cx.next_out = wp;
10503036ec7SBrian Somers state->cx.avail_out = DEFLATE_CHUNK_LEN - 2;
10603036ec7SBrian Somers state->cx.next_in = MBUF_CTOP(mi);
10726af0ae9SBrian Somers state->cx.avail_in = mi->m_len;
1080053cc58SBrian Somers flush = Z_NO_FLUSH;
1090053cc58SBrian Somers
1100053cc58SBrian Somers olen = 0;
1110053cc58SBrian Somers while (1) {
11203036ec7SBrian Somers if ((res = deflate(&state->cx, flush)) != Z_OK) {
1130053cc58SBrian Somers if (res == Z_STREAM_END)
1140053cc58SBrian Somers break; /* Done */
115a33b2ef7SBrian Somers log_Printf(LogWARN, "DeflateOutput: deflate returned %d (%s)\n",
11603036ec7SBrian Somers res, state->cx.msg ? state->cx.msg : "");
11726af0ae9SBrian Somers m_freem(mo_head);
11826af0ae9SBrian Somers m_free(mi_head);
11903036ec7SBrian Somers state->seqno--;
1205d9e6103SBrian Somers return mp; /* Our dictionary's probably dead now :-( */
1210053cc58SBrian Somers }
1220053cc58SBrian Somers
12303036ec7SBrian Somers if (flush == Z_SYNC_FLUSH && state->cx.avail_out != 0)
1240053cc58SBrian Somers break;
1250053cc58SBrian Somers
12626af0ae9SBrian Somers if (state->cx.avail_in == 0 && mi->m_next != NULL) {
12726af0ae9SBrian Somers mi = mi->m_next;
12803036ec7SBrian Somers state->cx.next_in = MBUF_CTOP(mi);
12926af0ae9SBrian Somers state->cx.avail_in = mi->m_len;
13026af0ae9SBrian Somers if (mi->m_next == NULL)
1310053cc58SBrian Somers flush = Z_SYNC_FLUSH;
1320053cc58SBrian Somers }
1330053cc58SBrian Somers
13403036ec7SBrian Somers if (state->cx.avail_out == 0) {
13526af0ae9SBrian Somers mo->m_next = m_get(DEFLATE_CHUNK_LEN, MB_CCPOUT);
13626af0ae9SBrian Somers olen += (mo->m_len = DEFLATE_CHUNK_LEN);
13726af0ae9SBrian Somers mo = mo->m_next;
13826af0ae9SBrian Somers mo->m_len = 0;
13903036ec7SBrian Somers state->cx.next_out = MBUF_CTOP(mo);
14003036ec7SBrian Somers state->cx.avail_out = DEFLATE_CHUNK_LEN;
1410053cc58SBrian Somers }
1420053cc58SBrian Somers }
1430053cc58SBrian Somers
14426af0ae9SBrian Somers olen += (mo->m_len = DEFLATE_CHUNK_LEN - state->cx.avail_out);
1450053cc58SBrian Somers olen -= 4; /* exclude the trailing EMPTY_BLOCK */
1460053cc58SBrian Somers
1470053cc58SBrian Somers /*
1480053cc58SBrian Somers * If the output packet (including seqno and excluding the EMPTY_BLOCK)
1490a1b5c9dSBrian Somers * got bigger, send the original.
1500053cc58SBrian Somers */
1510053cc58SBrian Somers if (olen >= ilen) {
15226af0ae9SBrian Somers m_freem(mo_head);
15326af0ae9SBrian Somers m_free(mi_head);
154dd7e2610SBrian Somers log_Printf(LogDEBUG, "DeflateOutput: %d => %d: Uncompressible (0x%04x)\n",
1555d9e6103SBrian Somers ilen, olen, *proto);
156f4768038SBrian Somers ccp->uncompout += ilen;
157f4768038SBrian Somers ccp->compout += ilen; /* We measure this stuff too */
1585d9e6103SBrian Somers return mp;
1590053cc58SBrian Somers }
1600053cc58SBrian Somers
16126af0ae9SBrian Somers m_freem(mi_head);
1620053cc58SBrian Somers
1630053cc58SBrian Somers /*
1640053cc58SBrian Somers * Lose the last four bytes of our output.
1650053cc58SBrian Somers * XXX: We should probably assert that these are the same as the
1660053cc58SBrian Somers * contents of EMPTY_BLOCK.
1670053cc58SBrian Somers */
16826af0ae9SBrian Somers mo = mo_head;
16926af0ae9SBrian Somers for (len = mo->m_len; len < olen; mo = mo->m_next, len += mo->m_len)
1700053cc58SBrian Somers ;
17126af0ae9SBrian Somers mo->m_len -= len - olen;
17226af0ae9SBrian Somers if (mo->m_next != NULL) {
17326af0ae9SBrian Somers m_freem(mo->m_next);
17426af0ae9SBrian Somers mo->m_next = NULL;
1750053cc58SBrian Somers }
1760053cc58SBrian Somers
177f4768038SBrian Somers ccp->uncompout += ilen;
178f4768038SBrian Somers ccp->compout += olen;
1790053cc58SBrian Somers
180dd7e2610SBrian Somers log_Printf(LogDEBUG, "DeflateOutput: %d => %d bytes, proto 0x%04x\n",
1815d9e6103SBrian Somers ilen, olen, *proto);
1820053cc58SBrian Somers
1835d9e6103SBrian Somers *proto = ccp_Proto(ccp);
1845d9e6103SBrian Somers return mo_head;
1850053cc58SBrian Somers }
1860053cc58SBrian Somers
1870053cc58SBrian Somers static void
DeflateResetInput(void * v)18803036ec7SBrian Somers DeflateResetInput(void *v)
1890053cc58SBrian Somers {
19003036ec7SBrian Somers struct deflate_state *state = (struct deflate_state *)v;
19103036ec7SBrian Somers
19203036ec7SBrian Somers state->seqno = 0;
19303036ec7SBrian Somers state->uncomp_rec = 0;
19403036ec7SBrian Somers inflateReset(&state->cx);
195dd7e2610SBrian Somers log_Printf(LogCCP, "Deflate: Input channel reset\n");
1960053cc58SBrian Somers }
1970053cc58SBrian Somers
1980053cc58SBrian Somers static struct mbuf *
DeflateInput(void * v,struct ccp * ccp,u_short * proto,struct mbuf * mi)19903036ec7SBrian Somers DeflateInput(void *v, struct ccp *ccp, u_short *proto, struct mbuf *mi)
2000053cc58SBrian Somers {
20103036ec7SBrian Somers struct deflate_state *state = (struct deflate_state *)v;
2020053cc58SBrian Somers struct mbuf *mo, *mo_head, *mi_head;
2030053cc58SBrian Somers u_char *wp;
2040053cc58SBrian Somers int ilen, olen;
2050053cc58SBrian Somers int seq, flush, res, first;
2060053cc58SBrian Somers u_char hdr[2];
2070053cc58SBrian Somers
208dd7e2610SBrian Somers log_DumpBp(LogDEBUG, "DeflateInput: Decompress packet:", mi);
209dd7e2610SBrian Somers mi_head = mi = mbuf_Read(mi, hdr, 2);
2100053cc58SBrian Somers ilen = 2;
2110053cc58SBrian Somers
2120053cc58SBrian Somers /* Check the sequence number. */
2130053cc58SBrian Somers seq = (hdr[0] << 8) + hdr[1];
214dd7e2610SBrian Somers log_Printf(LogDEBUG, "DeflateInput: Seq %d\n", seq);
21503036ec7SBrian Somers if (seq != state->seqno) {
21603036ec7SBrian Somers if (seq <= state->uncomp_rec)
21798baf7c8SBrian Somers /*
21898baf7c8SBrian Somers * So the peer's started at zero again - fine ! If we're wrong,
21998baf7c8SBrian Somers * inflate() will fail. This is better than getting into a loop
22098baf7c8SBrian Somers * trying to get a ResetReq to a busy sender.
22198baf7c8SBrian Somers */
22203036ec7SBrian Somers state->seqno = seq;
2231208d55bSBrian Somers else {
224a36ca3ccSBrian Somers log_Printf(LogCCP, "DeflateInput: Seq error: Got %d, expected %d\n",
22503036ec7SBrian Somers seq, state->seqno);
22626af0ae9SBrian Somers m_freem(mi_head);
227dd7e2610SBrian Somers ccp_SendResetReq(&ccp->fsm);
2280053cc58SBrian Somers return NULL;
2290053cc58SBrian Somers }
2301208d55bSBrian Somers }
23103036ec7SBrian Somers state->seqno++;
23203036ec7SBrian Somers state->uncomp_rec = 0;
2330053cc58SBrian Somers
2340053cc58SBrian Somers /* Allocate an output mbuf */
23526af0ae9SBrian Somers mo_head = mo = m_get(DEFLATE_CHUNK_LEN, MB_CCPIN);
2360053cc58SBrian Somers
2370053cc58SBrian Somers /* Our proto starts with 0 if it's compressed */
2380053cc58SBrian Somers wp = MBUF_CTOP(mo);
2390053cc58SBrian Somers wp[0] = '\0';
2400053cc58SBrian Somers
2410053cc58SBrian Somers /*
2420053cc58SBrian Somers * We set avail_out to 1 initially so we can look at the first
2430053cc58SBrian Somers * byte of the output and decide whether we have a compressed
2440053cc58SBrian Somers * proto field.
2450053cc58SBrian Somers */
24603036ec7SBrian Somers state->cx.next_in = MBUF_CTOP(mi);
24726af0ae9SBrian Somers state->cx.avail_in = mi->m_len;
24803036ec7SBrian Somers state->cx.next_out = wp + 1;
24903036ec7SBrian Somers state->cx.avail_out = 1;
25026af0ae9SBrian Somers ilen += mi->m_len;
2510053cc58SBrian Somers
25226af0ae9SBrian Somers flush = mi->m_next ? Z_NO_FLUSH : Z_SYNC_FLUSH;
2530053cc58SBrian Somers first = 1;
2540053cc58SBrian Somers olen = 0;
2550053cc58SBrian Somers
2560053cc58SBrian Somers while (1) {
25703036ec7SBrian Somers if ((res = inflate(&state->cx, flush)) != Z_OK) {
2580053cc58SBrian Somers if (res == Z_STREAM_END)
2590053cc58SBrian Somers break; /* Done */
260a36ca3ccSBrian Somers log_Printf(LogCCP, "DeflateInput: inflate returned %d (%s)\n",
26103036ec7SBrian Somers res, state->cx.msg ? state->cx.msg : "");
26226af0ae9SBrian Somers m_freem(mo_head);
26326af0ae9SBrian Somers m_freem(mi);
264dd7e2610SBrian Somers ccp_SendResetReq(&ccp->fsm);
2650053cc58SBrian Somers return NULL;
2660053cc58SBrian Somers }
2670053cc58SBrian Somers
26803036ec7SBrian Somers if (flush == Z_SYNC_FLUSH && state->cx.avail_out != 0)
2690053cc58SBrian Somers break;
2700053cc58SBrian Somers
27126af0ae9SBrian Somers if (state->cx.avail_in == 0 && mi && (mi = m_free(mi)) != NULL) {
2720053cc58SBrian Somers /* underflow */
27303036ec7SBrian Somers state->cx.next_in = MBUF_CTOP(mi);
27426af0ae9SBrian Somers ilen += (state->cx.avail_in = mi->m_len);
27526af0ae9SBrian Somers if (mi->m_next == NULL)
2760053cc58SBrian Somers flush = Z_SYNC_FLUSH;
2770053cc58SBrian Somers }
2780053cc58SBrian Somers
279e43ebac1SBrian Somers if (state->cx.avail_out == 0) {
2800053cc58SBrian Somers /* overflow */
2810053cc58SBrian Somers if (first) {
2820053cc58SBrian Somers if (!(wp[1] & 1)) {
2830053cc58SBrian Somers /* 2 byte proto, shuffle it back in output */
2840053cc58SBrian Somers wp[0] = wp[1];
28503036ec7SBrian Somers state->cx.next_out--;
28603036ec7SBrian Somers state->cx.avail_out = DEFLATE_CHUNK_LEN-1;
2870053cc58SBrian Somers } else
28803036ec7SBrian Somers state->cx.avail_out = DEFLATE_CHUNK_LEN-2;
2890053cc58SBrian Somers first = 0;
2900053cc58SBrian Somers } else {
29126af0ae9SBrian Somers olen += (mo->m_len = DEFLATE_CHUNK_LEN);
29226af0ae9SBrian Somers mo->m_next = m_get(DEFLATE_CHUNK_LEN, MB_CCPIN);
29326af0ae9SBrian Somers mo = mo->m_next;
29403036ec7SBrian Somers state->cx.next_out = MBUF_CTOP(mo);
29503036ec7SBrian Somers state->cx.avail_out = DEFLATE_CHUNK_LEN;
2960053cc58SBrian Somers }
2970053cc58SBrian Somers }
298c4c4aaacSBrian Somers }
2990053cc58SBrian Somers
3000053cc58SBrian Somers if (mi != NULL)
30126af0ae9SBrian Somers m_freem(mi);
3020053cc58SBrian Somers
3030053cc58SBrian Somers if (first) {
304a36ca3ccSBrian Somers log_Printf(LogCCP, "DeflateInput: Length error\n");
30526af0ae9SBrian Somers m_freem(mo_head);
306dd7e2610SBrian Somers ccp_SendResetReq(&ccp->fsm);
3070053cc58SBrian Somers return NULL;
3080053cc58SBrian Somers }
3090053cc58SBrian Somers
31026af0ae9SBrian Somers olen += (mo->m_len = DEFLATE_CHUNK_LEN - state->cx.avail_out);
3110053cc58SBrian Somers
3120053cc58SBrian Somers *proto = ((u_short)wp[0] << 8) | wp[1];
31326af0ae9SBrian Somers mo_head->m_offset += 2;
31426af0ae9SBrian Somers mo_head->m_len -= 2;
3150053cc58SBrian Somers olen -= 2;
3160053cc58SBrian Somers
317f4768038SBrian Somers ccp->compin += ilen;
318f4768038SBrian Somers ccp->uncompin += olen;
3190053cc58SBrian Somers
320dd7e2610SBrian Somers log_Printf(LogDEBUG, "DeflateInput: %d => %d bytes, proto 0x%04x\n",
3210053cc58SBrian Somers ilen, olen, *proto);
3220053cc58SBrian Somers
3230053cc58SBrian Somers /*
3240053cc58SBrian Somers * Simulate an EMPTY_BLOCK so that our dictionary stays in sync.
3250053cc58SBrian Somers * The peer will have silently removed this!
3260053cc58SBrian Somers */
32703036ec7SBrian Somers state->cx.next_out = garbage;
32803036ec7SBrian Somers state->cx.avail_out = sizeof garbage;
32903036ec7SBrian Somers state->cx.next_in = EMPTY_BLOCK;
33003036ec7SBrian Somers state->cx.avail_in = sizeof EMPTY_BLOCK;
33103036ec7SBrian Somers inflate(&state->cx, Z_SYNC_FLUSH);
3320053cc58SBrian Somers
3330053cc58SBrian Somers return mo_head;
3340053cc58SBrian Somers }
3350053cc58SBrian Somers
3360053cc58SBrian Somers static void
DeflateDictSetup(void * v,struct ccp * ccp,u_short proto,struct mbuf * mi)33703036ec7SBrian Somers DeflateDictSetup(void *v, struct ccp *ccp, u_short proto, struct mbuf *mi)
3380053cc58SBrian Somers {
33903036ec7SBrian Somers struct deflate_state *state = (struct deflate_state *)v;
340038a3666SBrian Somers int res, flush, expect_error;
3410053cc58SBrian Somers u_char *rp;
3420053cc58SBrian Somers struct mbuf *mi_head;
3430053cc58SBrian Somers short len;
3440053cc58SBrian Somers
345dd7e2610SBrian Somers log_Printf(LogDEBUG, "DeflateDictSetup: Got seq %d\n", state->seqno);
3460053cc58SBrian Somers
3470053cc58SBrian Somers /*
3480053cc58SBrian Somers * Stuff an ``uncompressed data'' block header followed by the
3490053cc58SBrian Somers * protocol in front of the input
3500053cc58SBrian Somers */
35126af0ae9SBrian Somers mi_head = m_get(7, MB_CCPOUT);
35226af0ae9SBrian Somers mi_head->m_next = mi;
35326af0ae9SBrian Somers len = m_length(mi);
3540053cc58SBrian Somers mi = mi_head;
3550053cc58SBrian Somers rp = MBUF_CTOP(mi);
3560053cc58SBrian Somers if (proto < 0x100) { /* Compress the protocol */
3570053cc58SBrian Somers rp[5] = proto & 0377;
35826af0ae9SBrian Somers mi->m_len = 6;
3590053cc58SBrian Somers len++;
3600053cc58SBrian Somers } else { /* Don't compress the protocol */
3610053cc58SBrian Somers rp[5] = proto >> 8;
3620053cc58SBrian Somers rp[6] = proto & 0377;
36326af0ae9SBrian Somers mi->m_len = 7;
3640053cc58SBrian Somers len += 2;
3650053cc58SBrian Somers }
3660053cc58SBrian Somers rp[0] = 0x80; /* BITS: 100xxxxx */
3670053cc58SBrian Somers rp[1] = len & 0377; /* The length */
3680053cc58SBrian Somers rp[2] = len >> 8;
3690053cc58SBrian Somers rp[3] = (~len) & 0377; /* One's compliment of the length */
3700053cc58SBrian Somers rp[4] = (~len) >> 8;
3710053cc58SBrian Somers
37203036ec7SBrian Somers state->cx.next_in = rp;
37326af0ae9SBrian Somers state->cx.avail_in = mi->m_len;
37403036ec7SBrian Somers state->cx.next_out = garbage;
37503036ec7SBrian Somers state->cx.avail_out = sizeof garbage;
3760053cc58SBrian Somers flush = Z_NO_FLUSH;
377038a3666SBrian Somers expect_error = 0;
3780053cc58SBrian Somers
3790053cc58SBrian Somers while (1) {
38003036ec7SBrian Somers if ((res = inflate(&state->cx, flush)) != Z_OK) {
3810053cc58SBrian Somers if (res == Z_STREAM_END)
3820053cc58SBrian Somers break; /* Done */
383038a3666SBrian Somers if (expect_error && res == Z_BUF_ERROR)
384038a3666SBrian Somers break;
385a36ca3ccSBrian Somers log_Printf(LogCCP, "DeflateDictSetup: inflate returned %d (%s)\n",
38603036ec7SBrian Somers res, state->cx.msg ? state->cx.msg : "");
387a36ca3ccSBrian Somers log_Printf(LogCCP, "DeflateDictSetup: avail_in %d, avail_out %d\n",
38803036ec7SBrian Somers state->cx.avail_in, state->cx.avail_out);
389dd7e2610SBrian Somers ccp_SendResetReq(&ccp->fsm);
39026af0ae9SBrian Somers m_free(mi_head); /* lose our allocated ``head'' buf */
3910053cc58SBrian Somers return;
3920053cc58SBrian Somers }
3930053cc58SBrian Somers
39403036ec7SBrian Somers if (flush == Z_SYNC_FLUSH && state->cx.avail_out != 0)
3950053cc58SBrian Somers break;
3960053cc58SBrian Somers
39726af0ae9SBrian Somers if (state->cx.avail_in == 0 && mi && (mi = mi->m_next) != NULL) {
3980053cc58SBrian Somers /* underflow */
39903036ec7SBrian Somers state->cx.next_in = MBUF_CTOP(mi);
40026af0ae9SBrian Somers state->cx.avail_in = mi->m_len;
40126af0ae9SBrian Somers if (mi->m_next == NULL)
4020053cc58SBrian Somers flush = Z_SYNC_FLUSH;
4030053cc58SBrian Somers }
4040053cc58SBrian Somers
40503036ec7SBrian Somers if (state->cx.avail_out == 0) {
40603036ec7SBrian Somers if (state->cx.avail_in == 0)
407038a3666SBrian Somers /*
408038a3666SBrian Somers * This seems to be a bug in libz ! If inflate() finished
409038a3666SBrian Somers * with 0 avail_in and 0 avail_out *and* this is the end of
410038a3666SBrian Somers * our input *and* inflate() *has* actually written all the
411038a3666SBrian Somers * output it's going to, it *doesn't* return Z_STREAM_END !
412038a3666SBrian Somers * When we subsequently call it with no more input, it gives
413038a3666SBrian Somers * us Z_BUF_ERROR :-( It seems pretty safe to ignore this
414038a3666SBrian Somers * error (the dictionary seems to stay in sync). In the worst
415038a3666SBrian Somers * case, we'll drop the next compressed packet and do a
416038a3666SBrian Somers * CcpReset() then.
417038a3666SBrian Somers */
418038a3666SBrian Somers expect_error = 1;
4190053cc58SBrian Somers /* overflow */
42003036ec7SBrian Somers state->cx.next_out = garbage;
42103036ec7SBrian Somers state->cx.avail_out = sizeof garbage;
4220053cc58SBrian Somers }
4230053cc58SBrian Somers }
4240053cc58SBrian Somers
425f4768038SBrian Somers ccp->compin += len;
426f4768038SBrian Somers ccp->uncompin += len;
4270053cc58SBrian Somers
42803036ec7SBrian Somers state->seqno++;
42903036ec7SBrian Somers state->uncomp_rec++;
43026af0ae9SBrian Somers m_free(mi_head); /* lose our allocated ``head'' buf */
4310053cc58SBrian Somers }
4320053cc58SBrian Somers
4330053cc58SBrian Somers static const char *
DeflateDispOpts(struct fsm_opt * o)434ff360cc9SBrian Somers DeflateDispOpts(struct fsm_opt *o)
4350053cc58SBrian Somers {
436d93d3a9cSBrian Somers static char disp[7]; /* Must be used immediately */
4370053cc58SBrian Somers
4380053cc58SBrian Somers sprintf(disp, "win %d", (o->data[0]>>4) + 8);
4390053cc58SBrian Somers return disp;
4400053cc58SBrian Somers }
4410053cc58SBrian Somers
4420053cc58SBrian Somers static void
DeflateInitOptsOutput(struct bundle * bundle __unused,struct fsm_opt * o,const struct ccp_config * cfg)443057f1760SBrian Somers DeflateInitOptsOutput(struct bundle *bundle __unused, struct fsm_opt *o,
4448fb5ef5aSBrian Somers const struct ccp_config *cfg)
4450053cc58SBrian Somers {
446ff360cc9SBrian Somers o->hdr.len = 4;
44703036ec7SBrian Somers o->data[0] = ((cfg->deflate.out.winsize - 8) << 4) + 8;
4484bc84b8cSBrian Somers o->data[1] = '\0';
4490053cc58SBrian Somers }
4500053cc58SBrian Somers
4510053cc58SBrian Somers static int
DeflateSetOptsOutput(struct bundle * bundle __unused,struct fsm_opt * o,const struct ccp_config * cfg __unused)452057f1760SBrian Somers DeflateSetOptsOutput(struct bundle *bundle __unused, struct fsm_opt *o,
453057f1760SBrian Somers const struct ccp_config *cfg __unused)
4540053cc58SBrian Somers {
455ff360cc9SBrian Somers if (o->hdr.len != 4 || (o->data[0] & 15) != 8 || o->data[1] != '\0')
4560053cc58SBrian Somers return MODE_REJ;
45703036ec7SBrian Somers
45803036ec7SBrian Somers if ((o->data[0] >> 4) + 8 > 15) {
45903036ec7SBrian Somers o->data[0] = ((15 - 8) << 4) + 8;
4600053cc58SBrian Somers return MODE_NAK;
4610053cc58SBrian Somers }
4620053cc58SBrian Somers
4630053cc58SBrian Somers return MODE_ACK;
4640053cc58SBrian Somers }
4650053cc58SBrian Somers
4660053cc58SBrian Somers static int
DeflateSetOptsInput(struct bundle * bundle __unused,struct fsm_opt * o,const struct ccp_config * cfg)467057f1760SBrian Somers DeflateSetOptsInput(struct bundle *bundle __unused, struct fsm_opt *o,
4688fb5ef5aSBrian Somers const struct ccp_config *cfg)
4690053cc58SBrian Somers {
47003036ec7SBrian Somers int want;
47103036ec7SBrian Somers
472ff360cc9SBrian Somers if (o->hdr.len != 4 || (o->data[0] & 15) != 8 || o->data[1] != '\0')
47303036ec7SBrian Somers return MODE_REJ;
47403036ec7SBrian Somers
47503036ec7SBrian Somers want = (o->data[0] >> 4) + 8;
47603036ec7SBrian Somers if (cfg->deflate.in.winsize == 0) {
47703036ec7SBrian Somers if (want < 8 || want > 15) {
47803036ec7SBrian Somers o->data[0] = ((15 - 8) << 4) + 8;
47903036ec7SBrian Somers }
48003036ec7SBrian Somers } else if (want != cfg->deflate.in.winsize) {
48103036ec7SBrian Somers o->data[0] = ((cfg->deflate.in.winsize - 8) << 4) + 8;
48203036ec7SBrian Somers return MODE_NAK;
4830053cc58SBrian Somers }
4840053cc58SBrian Somers
48503036ec7SBrian Somers return MODE_ACK;
4864bc84b8cSBrian Somers }
4874bc84b8cSBrian Somers
48803036ec7SBrian Somers static void *
DeflateInitInput(struct bundle * bundle __unused,struct fsm_opt * o)489057f1760SBrian Somers DeflateInitInput(struct bundle *bundle __unused, struct fsm_opt *o)
4904bc84b8cSBrian Somers {
49103036ec7SBrian Somers struct deflate_state *state;
49203036ec7SBrian Somers
49303036ec7SBrian Somers state = (struct deflate_state *)malloc(sizeof(struct deflate_state));
49403036ec7SBrian Somers if (state != NULL) {
49503036ec7SBrian Somers state->winsize = (o->data[0] >> 4) + 8;
49603036ec7SBrian Somers state->cx.zalloc = NULL;
49703036ec7SBrian Somers state->cx.opaque = NULL;
49803036ec7SBrian Somers state->cx.zfree = NULL;
49903036ec7SBrian Somers state->cx.next_out = NULL;
50003036ec7SBrian Somers if (inflateInit2(&state->cx, -state->winsize) == Z_OK)
50103036ec7SBrian Somers DeflateResetInput(state);
50203036ec7SBrian Somers else {
50303036ec7SBrian Somers free(state);
50403036ec7SBrian Somers state = NULL;
50503036ec7SBrian Somers }
5064bc84b8cSBrian Somers }
5074bc84b8cSBrian Somers
50803036ec7SBrian Somers return state;
5090053cc58SBrian Somers }
5100053cc58SBrian Somers
51103036ec7SBrian Somers static void *
DeflateInitOutput(struct bundle * bundle __unused,struct fsm_opt * o)512057f1760SBrian Somers DeflateInitOutput(struct bundle *bundle __unused, struct fsm_opt *o)
5130053cc58SBrian Somers {
51403036ec7SBrian Somers struct deflate_state *state;
51503036ec7SBrian Somers
51603036ec7SBrian Somers state = (struct deflate_state *)malloc(sizeof(struct deflate_state));
51703036ec7SBrian Somers if (state != NULL) {
51803036ec7SBrian Somers state->winsize = (o->data[0] >> 4) + 8;
51903036ec7SBrian Somers state->cx.zalloc = NULL;
52003036ec7SBrian Somers state->cx.opaque = NULL;
52103036ec7SBrian Somers state->cx.zfree = NULL;
52203036ec7SBrian Somers state->cx.next_in = NULL;
52303036ec7SBrian Somers if (deflateInit2(&state->cx, Z_DEFAULT_COMPRESSION, 8,
52403036ec7SBrian Somers -state->winsize, 8, Z_DEFAULT_STRATEGY) == Z_OK)
52503036ec7SBrian Somers DeflateResetOutput(state);
52603036ec7SBrian Somers else {
52703036ec7SBrian Somers free(state);
52803036ec7SBrian Somers state = NULL;
52903036ec7SBrian Somers }
5300053cc58SBrian Somers }
5310053cc58SBrian Somers
53203036ec7SBrian Somers return state;
5330053cc58SBrian Somers }
5340053cc58SBrian Somers
5350053cc58SBrian Somers static void
DeflateTermInput(void * v)53603036ec7SBrian Somers DeflateTermInput(void *v)
5370053cc58SBrian Somers {
53803036ec7SBrian Somers struct deflate_state *state = (struct deflate_state *)v;
53903036ec7SBrian Somers
54003036ec7SBrian Somers inflateEnd(&state->cx);
54103036ec7SBrian Somers free(state);
5420053cc58SBrian Somers }
5430053cc58SBrian Somers
5440053cc58SBrian Somers static void
DeflateTermOutput(void * v)54503036ec7SBrian Somers DeflateTermOutput(void *v)
5460053cc58SBrian Somers {
54703036ec7SBrian Somers struct deflate_state *state = (struct deflate_state *)v;
54803036ec7SBrian Somers
54903036ec7SBrian Somers deflateEnd(&state->cx);
55003036ec7SBrian Somers free(state);
5510053cc58SBrian Somers }
5520053cc58SBrian Somers
5534bc84b8cSBrian Somers const struct ccp_algorithm PppdDeflateAlgorithm = {
5547f89db65SBrian Somers TY_PPPD_DEFLATE, /* Older versions of pppd expected this ``type'' */
5551342caedSBrian Somers CCP_NEG_DEFLATE24,
5564bc84b8cSBrian Somers DeflateDispOpts,
5576cf6ee76SBrian Somers ccp_DefaultUsable,
5586cf6ee76SBrian Somers ccp_DefaultRequired,
5594bc84b8cSBrian Somers {
56003036ec7SBrian Somers DeflateSetOptsInput,
5614bc84b8cSBrian Somers DeflateInitInput,
5624bc84b8cSBrian Somers DeflateTermInput,
5634bc84b8cSBrian Somers DeflateResetInput,
5644bc84b8cSBrian Somers DeflateInput,
5654bc84b8cSBrian Somers DeflateDictSetup
5664bc84b8cSBrian Somers },
5674bc84b8cSBrian Somers {
5686301d506SBrian Somers 0,
56903036ec7SBrian Somers DeflateInitOptsOutput,
57003036ec7SBrian Somers DeflateSetOptsOutput,
5714bc84b8cSBrian Somers DeflateInitOutput,
5724bc84b8cSBrian Somers DeflateTermOutput,
5734bc84b8cSBrian Somers DeflateResetOutput,
5744bc84b8cSBrian Somers DeflateOutput
5754bc84b8cSBrian Somers },
5764bc84b8cSBrian Somers };
5774bc84b8cSBrian Somers
5780053cc58SBrian Somers const struct ccp_algorithm DeflateAlgorithm = {
5794bc84b8cSBrian Somers TY_DEFLATE, /* rfc 1979 */
5801342caedSBrian Somers CCP_NEG_DEFLATE,
5810053cc58SBrian Somers DeflateDispOpts,
5826cf6ee76SBrian Somers ccp_DefaultUsable,
5836cf6ee76SBrian Somers ccp_DefaultRequired,
5840053cc58SBrian Somers {
58503036ec7SBrian Somers DeflateSetOptsInput,
5860053cc58SBrian Somers DeflateInitInput,
5870053cc58SBrian Somers DeflateTermInput,
5880053cc58SBrian Somers DeflateResetInput,
5890053cc58SBrian Somers DeflateInput,
5900053cc58SBrian Somers DeflateDictSetup
5910053cc58SBrian Somers },
5920053cc58SBrian Somers {
5936301d506SBrian Somers 0,
59403036ec7SBrian Somers DeflateInitOptsOutput,
59503036ec7SBrian Somers DeflateSetOptsOutput,
5960053cc58SBrian Somers DeflateInitOutput,
5970053cc58SBrian Somers DeflateTermOutput,
5980053cc58SBrian Somers DeflateResetOutput,
5990053cc58SBrian Somers DeflateOutput
6000053cc58SBrian Somers },
6010053cc58SBrian Somers };
602