2 * Copyright (c) 1997 Brian Somers <brian@Awfulhak.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
26 * $FreeBSD: src/usr.sbin/ppp/deflate.c,v 1.18.2.4 2002/09/01 02:12:26 brian Exp $
27 * $DragonFly: src/usr.sbin/ppp/deflate.c,v 1.2 2003/06/17 04:30:00 dillon Exp $
30 #include <sys/types.h>
44 struct deflate_state
{
51 static char garbage
[10];
52 static u_char EMPTY_BLOCK
[4] = { 0x00, 0x00, 0xff, 0xff };
54 #define DEFLATE_CHUNK_LEN (1536 - sizeof(struct mbuf))
57 DeflateResetOutput(void *v
)
59 struct deflate_state
*state
= (struct deflate_state
*)v
;
62 state
->uncomp_rec
= 0;
63 deflateReset(&state
->cx
);
64 log_Printf(LogCCP
, "Deflate: Output channel reset\n");
66 return 1; /* Ask FSM to ACK */
70 DeflateOutput(void *v
, struct ccp
*ccp
, struct link
*l
, int pri
, u_short
*proto
,
73 struct deflate_state
*state
= (struct deflate_state
*)v
;
75 int olen
, ilen
, len
, res
, flush
;
76 struct mbuf
*mo_head
, *mo
, *mi_head
, *mi
;
79 log_Printf(LogDEBUG
, "DeflateOutput: Proto %02x (%d bytes)\n", *proto
, ilen
);
80 log_DumpBp(LogDEBUG
, "DeflateOutput: Compress packet:", mp
);
82 /* Stuff the protocol in front of the input */
83 mi_head
= mi
= m_get(2, MB_CCPOUT
);
86 if (*proto
< 0x100) { /* Compress the protocol */
87 rp
[0] = *proto
& 0377;
89 } else { /* Don't compress the protocol */
91 rp
[1] = *proto
& 0377;
95 /* Allocate the initial output mbuf */
96 mo_head
= mo
= m_get(DEFLATE_CHUNK_LEN
, MB_CCPOUT
);
99 *wp
++ = state
->seqno
>> 8;
100 *wp
++ = state
->seqno
& 0377;
101 log_Printf(LogDEBUG
, "DeflateOutput: Seq %d\n", state
->seqno
);
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
->m_len
;
113 if ((res
= deflate(&state
->cx
, flush
)) != Z_OK
) {
114 if (res
== Z_STREAM_END
)
116 log_Printf(LogWARN
, "DeflateOutput: deflate returned %d (%s)\n",
117 res
, state
->cx
.msg
? state
->cx
.msg
: "");
121 return mp
; /* Our dictionary's probably dead now :-( */
124 if (flush
== Z_SYNC_FLUSH
&& state
->cx
.avail_out
!= 0)
127 if (state
->cx
.avail_in
== 0 && mi
->m_next
!= NULL
) {
129 state
->cx
.next_in
= MBUF_CTOP(mi
);
130 state
->cx
.avail_in
= mi
->m_len
;
131 if (mi
->m_next
== NULL
)
132 flush
= Z_SYNC_FLUSH
;
135 if (state
->cx
.avail_out
== 0) {
136 mo
->m_next
= m_get(DEFLATE_CHUNK_LEN
, MB_CCPOUT
);
137 olen
+= (mo
->m_len
= DEFLATE_CHUNK_LEN
);
140 state
->cx
.next_out
= MBUF_CTOP(mo
);
141 state
->cx
.avail_out
= DEFLATE_CHUNK_LEN
;
145 olen
+= (mo
->m_len
= DEFLATE_CHUNK_LEN
- state
->cx
.avail_out
);
146 olen
-= 4; /* exclude the trailing EMPTY_BLOCK */
149 * If the output packet (including seqno and excluding the EMPTY_BLOCK)
150 * got bigger, send the original.
155 log_Printf(LogDEBUG
, "DeflateOutput: %d => %d: Uncompressible (0x%04x)\n",
157 ccp
->uncompout
+= ilen
;
158 ccp
->compout
+= ilen
; /* We measure this stuff too */
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.
170 for (len
= mo
->m_len
; len
< olen
; mo
= mo
->m_next
, len
+= mo
->m_len
)
172 mo
->m_len
-= len
- olen
;
173 if (mo
->m_next
!= NULL
) {
178 ccp
->uncompout
+= ilen
;
179 ccp
->compout
+= olen
;
181 log_Printf(LogDEBUG
, "DeflateOutput: %d => %d bytes, proto 0x%04x\n",
184 *proto
= ccp_Proto(ccp
);
189 DeflateResetInput(void *v
)
191 struct deflate_state
*state
= (struct deflate_state
*)v
;
194 state
->uncomp_rec
= 0;
195 inflateReset(&state
->cx
);
196 log_Printf(LogCCP
, "Deflate: Input channel reset\n");
200 DeflateInput(void *v
, struct ccp
*ccp
, u_short
*proto
, struct mbuf
*mi
)
202 struct deflate_state
*state
= (struct deflate_state
*)v
;
203 struct mbuf
*mo
, *mo_head
, *mi_head
;
206 int seq
, flush
, res
, first
;
209 log_DumpBp(LogDEBUG
, "DeflateInput: Decompress packet:", mi
);
210 mi_head
= mi
= mbuf_Read(mi
, hdr
, 2);
213 /* Check the sequence number. */
214 seq
= (hdr
[0] << 8) + hdr
[1];
215 log_Printf(LogDEBUG
, "DeflateInput: Seq %d\n", seq
);
216 if (seq
!= state
->seqno
) {
217 if (seq
<= state
->uncomp_rec
)
219 * So the peer's started at zero again - fine ! If we're wrong,
220 * inflate() will fail. This is better than getting into a loop
221 * trying to get a ResetReq to a busy sender.
225 log_Printf(LogCCP
, "DeflateInput: Seq error: Got %d, expected %d\n",
228 ccp_SendResetReq(&ccp
->fsm
);
233 state
->uncomp_rec
= 0;
235 /* Allocate an output mbuf */
236 mo_head
= mo
= m_get(DEFLATE_CHUNK_LEN
, MB_CCPIN
);
238 /* Our proto starts with 0 if it's compressed */
243 * We set avail_out to 1 initially so we can look at the first
244 * byte of the output and decide whether we have a compressed
247 state
->cx
.next_in
= MBUF_CTOP(mi
);
248 state
->cx
.avail_in
= mi
->m_len
;
249 state
->cx
.next_out
= wp
+ 1;
250 state
->cx
.avail_out
= 1;
253 flush
= mi
->m_next
? Z_NO_FLUSH
: Z_SYNC_FLUSH
;
258 if ((res
= inflate(&state
->cx
, flush
)) != Z_OK
) {
259 if (res
== Z_STREAM_END
)
261 log_Printf(LogCCP
, "DeflateInput: inflate returned %d (%s)\n",
262 res
, state
->cx
.msg
? state
->cx
.msg
: "");
265 ccp_SendResetReq(&ccp
->fsm
);
269 if (flush
== Z_SYNC_FLUSH
&& state
->cx
.avail_out
!= 0)
272 if (state
->cx
.avail_in
== 0 && mi
&& (mi
= m_free(mi
)) != NULL
) {
274 state
->cx
.next_in
= MBUF_CTOP(mi
);
275 ilen
+= (state
->cx
.avail_in
= mi
->m_len
);
276 if (mi
->m_next
== NULL
)
277 flush
= Z_SYNC_FLUSH
;
280 if (state
->cx
.avail_out
== 0) {
284 /* 2 byte proto, shuffle it back in output */
286 state
->cx
.next_out
--;
287 state
->cx
.avail_out
= DEFLATE_CHUNK_LEN
-1;
289 state
->cx
.avail_out
= DEFLATE_CHUNK_LEN
-2;
292 olen
+= (mo
->m_len
= DEFLATE_CHUNK_LEN
);
293 mo
->m_next
= m_get(DEFLATE_CHUNK_LEN
, MB_CCPIN
);
295 state
->cx
.next_out
= MBUF_CTOP(mo
);
296 state
->cx
.avail_out
= DEFLATE_CHUNK_LEN
;
305 log_Printf(LogCCP
, "DeflateInput: Length error\n");
307 ccp_SendResetReq(&ccp
->fsm
);
311 olen
+= (mo
->m_len
= DEFLATE_CHUNK_LEN
- state
->cx
.avail_out
);
313 *proto
= ((u_short
)wp
[0] << 8) | wp
[1];
314 mo_head
->m_offset
+= 2;
319 ccp
->uncompin
+= olen
;
321 log_Printf(LogDEBUG
, "DeflateInput: %d => %d bytes, proto 0x%04x\n",
325 * Simulate an EMPTY_BLOCK so that our dictionary stays in sync.
326 * The peer will have silently removed this!
328 state
->cx
.next_out
= garbage
;
329 state
->cx
.avail_out
= sizeof garbage
;
330 state
->cx
.next_in
= EMPTY_BLOCK
;
331 state
->cx
.avail_in
= sizeof EMPTY_BLOCK
;
332 inflate(&state
->cx
, Z_SYNC_FLUSH
);
338 DeflateDictSetup(void *v
, struct ccp
*ccp
, u_short proto
, struct mbuf
*mi
)
340 struct deflate_state
*state
= (struct deflate_state
*)v
;
341 int res
, flush
, expect_error
;
343 struct mbuf
*mi_head
;
346 log_Printf(LogDEBUG
, "DeflateDictSetup: Got seq %d\n", state
->seqno
);
349 * Stuff an ``uncompressed data'' block header followed by the
350 * protocol in front of the input
352 mi_head
= m_get(7, MB_CCPOUT
);
353 mi_head
->m_next
= mi
;
357 if (proto
< 0x100) { /* Compress the protocol */
358 rp
[5] = proto
& 0377;
361 } else { /* Don't compress the protocol */
363 rp
[6] = proto
& 0377;
367 rp
[0] = 0x80; /* BITS: 100xxxxx */
368 rp
[1] = len
& 0377; /* The length */
370 rp
[3] = (~len
) & 0377; /* One's compliment of the length */
373 state
->cx
.next_in
= rp
;
374 state
->cx
.avail_in
= mi
->m_len
;
375 state
->cx
.next_out
= garbage
;
376 state
->cx
.avail_out
= sizeof garbage
;
381 if ((res
= inflate(&state
->cx
, flush
)) != Z_OK
) {
382 if (res
== Z_STREAM_END
)
384 if (expect_error
&& res
== Z_BUF_ERROR
)
386 log_Printf(LogCCP
, "DeflateDictSetup: inflate returned %d (%s)\n",
387 res
, state
->cx
.msg
? state
->cx
.msg
: "");
388 log_Printf(LogCCP
, "DeflateDictSetup: avail_in %d, avail_out %d\n",
389 state
->cx
.avail_in
, state
->cx
.avail_out
);
390 ccp_SendResetReq(&ccp
->fsm
);
391 m_free(mi_head
); /* lose our allocated ``head'' buf */
395 if (flush
== Z_SYNC_FLUSH
&& state
->cx
.avail_out
!= 0)
398 if (state
->cx
.avail_in
== 0 && mi
&& (mi
= mi
->m_next
) != NULL
) {
400 state
->cx
.next_in
= MBUF_CTOP(mi
);
401 state
->cx
.avail_in
= mi
->m_len
;
402 if (mi
->m_next
== NULL
)
403 flush
= Z_SYNC_FLUSH
;
406 if (state
->cx
.avail_out
== 0) {
407 if (state
->cx
.avail_in
== 0)
409 * This seems to be a bug in libz ! If inflate() finished
410 * with 0 avail_in and 0 avail_out *and* this is the end of
411 * our input *and* inflate() *has* actually written all the
412 * output it's going to, it *doesn't* return Z_STREAM_END !
413 * When we subsequently call it with no more input, it gives
414 * us Z_BUF_ERROR :-( It seems pretty safe to ignore this
415 * error (the dictionary seems to stay in sync). In the worst
416 * case, we'll drop the next compressed packet and do a
421 state
->cx
.next_out
= garbage
;
422 state
->cx
.avail_out
= sizeof garbage
;
427 ccp
->uncompin
+= len
;
431 m_free(mi_head
); /* lose our allocated ``head'' buf */
435 DeflateDispOpts(struct fsm_opt
*o
)
437 static char disp
[7]; /* Must be used immediately */
439 sprintf(disp
, "win %d", (o
->data
[0]>>4) + 8);
444 DeflateInitOptsOutput(struct bundle
*bundle
, struct fsm_opt
*o
,
445 const struct ccp_config
*cfg
)
448 o
->data
[0] = ((cfg
->deflate
.out
.winsize
- 8) << 4) + 8;
453 DeflateSetOptsOutput(struct bundle
*bundle
, struct fsm_opt
*o
,
454 const struct ccp_config
*cfg
)
456 if (o
->hdr
.len
!= 4 || (o
->data
[0] & 15) != 8 || o
->data
[1] != '\0')
459 if ((o
->data
[0] >> 4) + 8 > 15) {
460 o
->data
[0] = ((15 - 8) << 4) + 8;
468 DeflateSetOptsInput(struct bundle
*bundle
, struct fsm_opt
*o
,
469 const struct ccp_config
*cfg
)
473 if (o
->hdr
.len
!= 4 || (o
->data
[0] & 15) != 8 || o
->data
[1] != '\0')
476 want
= (o
->data
[0] >> 4) + 8;
477 if (cfg
->deflate
.in
.winsize
== 0) {
478 if (want
< 8 || want
> 15) {
479 o
->data
[0] = ((15 - 8) << 4) + 8;
481 } else if (want
!= cfg
->deflate
.in
.winsize
) {
482 o
->data
[0] = ((cfg
->deflate
.in
.winsize
- 8) << 4) + 8;
490 DeflateInitInput(struct bundle
*bundle
, struct fsm_opt
*o
)
492 struct deflate_state
*state
;
494 state
= (struct deflate_state
*)malloc(sizeof(struct deflate_state
));
496 state
->winsize
= (o
->data
[0] >> 4) + 8;
497 state
->cx
.zalloc
= NULL
;
498 state
->cx
.opaque
= NULL
;
499 state
->cx
.zfree
= NULL
;
500 state
->cx
.next_out
= NULL
;
501 if (inflateInit2(&state
->cx
, -state
->winsize
) == Z_OK
)
502 DeflateResetInput(state
);
513 DeflateInitOutput(struct bundle
*bundle
, struct fsm_opt
*o
)
515 struct deflate_state
*state
;
517 state
= (struct deflate_state
*)malloc(sizeof(struct deflate_state
));
519 state
->winsize
= (o
->data
[0] >> 4) + 8;
520 state
->cx
.zalloc
= NULL
;
521 state
->cx
.opaque
= NULL
;
522 state
->cx
.zfree
= NULL
;
523 state
->cx
.next_in
= NULL
;
524 if (deflateInit2(&state
->cx
, Z_DEFAULT_COMPRESSION
, 8,
525 -state
->winsize
, 8, Z_DEFAULT_STRATEGY
) == Z_OK
)
526 DeflateResetOutput(state
);
537 DeflateTermInput(void *v
)
539 struct deflate_state
*state
= (struct deflate_state
*)v
;
541 inflateEnd(&state
->cx
);
546 DeflateTermOutput(void *v
)
548 struct deflate_state
*state
= (struct deflate_state
*)v
;
550 deflateEnd(&state
->cx
);
554 const struct ccp_algorithm PppdDeflateAlgorithm
= {
555 TY_PPPD_DEFLATE
, /* Older versions of pppd expected this ``type'' */
570 DeflateInitOptsOutput
,
571 DeflateSetOptsOutput
,
579 const struct ccp_algorithm DeflateAlgorithm
= {
580 TY_DEFLATE
, /* rfc 1979 */
595 DeflateInitOptsOutput
,
596 DeflateSetOptsOutput
,