2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 * ppp_deflate.c - interface the zlib procedures for Deflate compression
30 * and decompression (as used by gzip) to the PPP code.
31 * This version is for use with mbufs on BSD-derived systems.
33 * Copyright (c) 1994 The Australian National University.
34 * All rights reserved.
36 * Permission to use, copy, modify, and distribute this software and its
37 * documentation is hereby granted, provided that the above copyright
38 * notice appears in all copies. This software is provided without any
39 * warranty, express or implied. The Australian National University
40 * makes no representations about the suitability of this software for
43 * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
44 * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
45 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
46 * THE AUSTRALIAN NATIONAL UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY
49 * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
50 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
51 * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
52 * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
53 * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
57 #include <sys/param.h>
58 #include <sys/systm.h>
59 #include <sys/malloc.h>
61 #include <net/ppp_defs.h>
64 #define PACKETPTR struct mbuf *
65 #include <net/ppp_comp.h>
69 #define DEFLATE_DEBUG 1
72 * State for a Deflate (de)compressor.
74 struct deflate_state
{
82 struct compstat stats
;
85 #define DEFLATE_OVHD 2 /* Deflate overhead/packet */
87 static void *z_alloc(void *, u_int items
, u_int size
);
88 static void z_free(void *, void *ptr
);
89 static void *z_comp_alloc(u_char
*options
, int opt_len
);
90 static void *z_decomp_alloc(u_char
*options
, int opt_len
);
91 static void z_comp_free(void *state
);
92 static void z_decomp_free(void *state
);
93 static int z_comp_init(void *state
, u_char
*options
, int opt_len
,
94 int unit
, int hdrlen
, int debug
);
95 static int z_decomp_init(void *state
, u_char
*options
, int opt_len
,
96 int unit
, int hdrlen
, int mru
, int debug
);
97 static int z_compress(void *state
, struct mbuf
**mret
,
98 struct mbuf
*mp
, int slen
, int maxolen
);
99 static void z_incomp(void *state
, struct mbuf
*dmsg
);
100 static int z_decompress(void *state
, struct mbuf
*cmp
, struct mbuf
**dmpp
);
101 static void z_comp_reset(void *state
);
102 static void z_decomp_reset(void *state
);
103 static void z_comp_stats(void *state
, struct compstat
*stats
);
106 * Procedures exported to if_ppp.c.
108 struct compressor ppp_deflate
= {
109 CI_DEFLATE
, /* compress_proto */
110 z_comp_alloc
, /* comp_alloc */
111 z_comp_free
, /* comp_free */
112 z_comp_init
, /* comp_init */
113 z_comp_reset
, /* comp_reset */
114 z_compress
, /* compress */
115 z_comp_stats
, /* comp_stat */
116 z_decomp_alloc
, /* decomp_alloc */
117 z_decomp_free
, /* decomp_free */
118 z_decomp_init
, /* decomp_init */
119 z_decomp_reset
, /* decomp_reset */
120 z_decompress
, /* decompress */
121 z_incomp
, /* incomp */
122 z_comp_stats
, /* decomp_stat */
125 struct compressor ppp_deflate_draft
= {
126 CI_DEFLATE_DRAFT
, /* compress_proto */
127 z_comp_alloc
, /* comp_alloc */
128 z_comp_free
, /* comp_free */
129 z_comp_init
, /* comp_init */
130 z_comp_reset
, /* comp_reset */
131 z_compress
, /* compress */
132 z_comp_stats
, /* comp_stat */
133 z_decomp_alloc
, /* decomp_alloc */
134 z_decomp_free
, /* decomp_free */
135 z_decomp_init
, /* decomp_init */
136 z_decomp_reset
, /* decomp_reset */
137 z_decompress
, /* decompress */
138 z_incomp
, /* incomp */
139 z_comp_stats
, /* decomp_stat */
143 * Space allocation and freeing routines for use by zlib routines.
146 z_alloc(notused
, items
, size
)
152 MALLOC(ptr
, void *, items
* size
, M_DEVBUF
, M_NOWAIT
);
165 * Allocate space for a compressor.
168 z_comp_alloc(options
, opt_len
)
172 struct deflate_state
*state
;
175 if (opt_len
!= CILEN_DEFLATE
176 || (options
[0] != CI_DEFLATE
&& options
[0] != CI_DEFLATE_DRAFT
)
177 || options
[1] != CILEN_DEFLATE
178 || DEFLATE_METHOD(options
[2]) != DEFLATE_METHOD_VAL
179 || options
[3] != DEFLATE_CHK_SEQUENCE
)
181 w_size
= DEFLATE_SIZE(options
[2]);
182 if (w_size
< DEFLATE_MIN_SIZE
|| w_size
> DEFLATE_MAX_SIZE
)
185 MALLOC(state
, struct deflate_state
*, sizeof(struct deflate_state
),
190 state
->strm
.next_in
= NULL
;
191 state
->strm
.zalloc
= z_alloc
;
192 state
->strm
.zfree
= z_free
;
193 if (deflateInit2(&state
->strm
, Z_DEFAULT_COMPRESSION
, DEFLATE_METHOD_VAL
,
194 -w_size
, 8, Z_DEFAULT_STRATEGY
) != Z_OK
) {
195 FREE(state
, M_DEVBUF
);
199 state
->w_size
= w_size
;
200 bzero(&state
->stats
, sizeof(state
->stats
));
201 return (void *) state
;
208 struct deflate_state
*state
= (struct deflate_state
*) arg
;
210 deflateEnd(&state
->strm
);
211 FREE(state
, M_DEVBUF
);
215 z_comp_init(arg
, options
, opt_len
, unit
, hdrlen
, debug
)
218 int opt_len
, unit
, hdrlen
, debug
;
220 struct deflate_state
*state
= (struct deflate_state
*) arg
;
222 if (opt_len
< CILEN_DEFLATE
223 || (options
[0] != CI_DEFLATE
&& options
[0] != CI_DEFLATE_DRAFT
)
224 || options
[1] != CILEN_DEFLATE
225 || DEFLATE_METHOD(options
[2]) != DEFLATE_METHOD_VAL
226 || DEFLATE_SIZE(options
[2]) != state
->w_size
227 || options
[3] != DEFLATE_CHK_SEQUENCE
)
232 state
->hdrlen
= hdrlen
;
233 state
->debug
= debug
;
235 deflateReset(&state
->strm
);
244 struct deflate_state
*state
= (struct deflate_state
*) arg
;
247 deflateReset(&state
->strm
);
251 z_compress(arg
, mret
, mp
, orig_len
, maxolen
)
253 struct mbuf
**mret
; /* compressed packet (out) */
254 struct mbuf
*mp
; /* uncompressed packet (in) */
255 int orig_len
, maxolen
;
257 struct deflate_state
*state
= (struct deflate_state
*) arg
;
259 int proto
, olen
, wspace
, r
, flush
;
263 * Check that the protocol is in the range we handle.
265 rptr
= mtod(mp
, u_char
*);
266 proto
= PPP_PROTOCOL(rptr
);
267 if (proto
> 0x3fff || proto
== 0xfd || proto
== 0xfb) {
272 /* Allocate one mbuf initially. */
273 if (maxolen
> orig_len
)
275 MGET(m
, M_DONTWAIT
, MT_DATA
);
279 if (maxolen
+ state
->hdrlen
> MLEN
)
280 MCLGET(m
, M_DONTWAIT
);
281 wspace
= M_TRAILINGSPACE(m
);
282 if (state
->hdrlen
+ PPP_HDRLEN
+ 2 < wspace
) {
283 m
->m_data
+= state
->hdrlen
;
284 wspace
-= state
->hdrlen
;
286 wptr
= mtod(m
, u_char
*);
289 * Copy over the PPP header and store the 2-byte sequence number.
291 wptr
[0] = PPP_ADDRESS(rptr
);
292 wptr
[1] = PPP_CONTROL(rptr
);
293 wptr
[2] = PPP_COMP
>> 8;
296 wptr
[0] = state
->seqno
>> 8;
297 wptr
[1] = state
->seqno
;
299 state
->strm
.next_out
= wptr
;
300 state
->strm
.avail_out
= wspace
- (PPP_HDRLEN
+ 2);
302 state
->strm
.next_out
= NULL
;
303 state
->strm
.avail_out
= 1000000;
309 rptr
+= (proto
> 0xff)? 2: 3; /* skip 1st proto byte if 0 */
310 state
->strm
.next_in
= rptr
;
311 state
->strm
.avail_in
= mtod(mp
, u_char
*) + mp
->m_len
- rptr
;
313 flush
= (mp
== NULL
)? Z_PACKET_FLUSH
: Z_NO_FLUSH
;
316 r
= deflate(&state
->strm
, flush
);
318 printf("z_compress: deflate returned %d (%s)\n",
319 r
, (state
->strm
.msg
? state
->strm
.msg
: ""));
322 if (flush
!= Z_NO_FLUSH
&& state
->strm
.avail_out
!= 0)
323 break; /* all done */
324 if (state
->strm
.avail_in
== 0 && mp
!= NULL
) {
325 state
->strm
.next_in
= mtod(mp
, u_char
*);
326 state
->strm
.avail_in
= mp
->m_len
;
329 flush
= Z_PACKET_FLUSH
;
331 if (state
->strm
.avail_out
== 0) {
335 MGET(m
->m_next
, M_DONTWAIT
, MT_DATA
);
339 if (maxolen
- olen
> MLEN
)
340 MCLGET(m
, M_DONTWAIT
);
341 state
->strm
.next_out
= mtod(m
, u_char
*);
342 state
->strm
.avail_out
= wspace
= M_TRAILINGSPACE(m
);
346 state
->strm
.next_out
= NULL
;
347 state
->strm
.avail_out
= 1000000;
352 olen
+= (m
->m_len
= wspace
- state
->strm
.avail_out
);
355 * See if we managed to reduce the size of the packet.
357 if (m
!= NULL
&& olen
< orig_len
) {
358 state
->stats
.comp_bytes
+= olen
;
359 state
->stats
.comp_packets
++;
365 state
->stats
.inc_bytes
+= orig_len
;
366 state
->stats
.inc_packets
++;
369 state
->stats
.unc_bytes
+= orig_len
;
370 state
->stats
.unc_packets
++;
376 z_comp_stats(arg
, stats
)
378 struct compstat
*stats
;
380 struct deflate_state
*state
= (struct deflate_state
*) arg
;
383 *stats
= state
->stats
;
384 stats
->ratio
= stats
->unc_bytes
;
385 out
= stats
->comp_bytes
+ stats
->inc_bytes
;
386 if (stats
->ratio
<= 0x7ffffff)
395 * Allocate space for a decompressor.
398 z_decomp_alloc(options
, opt_len
)
402 struct deflate_state
*state
;
405 if (opt_len
!= CILEN_DEFLATE
406 || (options
[0] != CI_DEFLATE
&& options
[0] != CI_DEFLATE_DRAFT
)
407 || options
[1] != CILEN_DEFLATE
408 || DEFLATE_METHOD(options
[2]) != DEFLATE_METHOD_VAL
409 || options
[3] != DEFLATE_CHK_SEQUENCE
)
411 w_size
= DEFLATE_SIZE(options
[2]);
412 if (w_size
< DEFLATE_MIN_SIZE
|| w_size
> DEFLATE_MAX_SIZE
)
415 MALLOC(state
, struct deflate_state
*, sizeof(struct deflate_state
),
420 state
->strm
.next_out
= NULL
;
421 state
->strm
.zalloc
= z_alloc
;
422 state
->strm
.zfree
= z_free
;
423 if (inflateInit2(&state
->strm
, -w_size
) != Z_OK
) {
424 FREE(state
, M_DEVBUF
);
428 state
->w_size
= w_size
;
429 bzero(&state
->stats
, sizeof(state
->stats
));
430 return (void *) state
;
437 struct deflate_state
*state
= (struct deflate_state
*) arg
;
439 inflateEnd(&state
->strm
);
440 FREE(state
, M_DEVBUF
);
444 z_decomp_init(arg
, options
, opt_len
, unit
, hdrlen
, mru
, debug
)
447 int opt_len
, unit
, hdrlen
, mru
, debug
;
449 struct deflate_state
*state
= (struct deflate_state
*) arg
;
451 if (opt_len
< CILEN_DEFLATE
452 || (options
[0] != CI_DEFLATE
&& options
[0] != CI_DEFLATE_DRAFT
)
453 || options
[1] != CILEN_DEFLATE
454 || DEFLATE_METHOD(options
[2]) != DEFLATE_METHOD_VAL
455 || DEFLATE_SIZE(options
[2]) != state
->w_size
456 || options
[3] != DEFLATE_CHK_SEQUENCE
)
461 state
->hdrlen
= hdrlen
;
462 state
->debug
= debug
;
465 inflateReset(&state
->strm
);
474 struct deflate_state
*state
= (struct deflate_state
*) arg
;
477 inflateReset(&state
->strm
);
481 * Decompress a Deflate-compressed packet.
483 * Because of patent problems, we return DECOMP_ERROR for errors
484 * found by inspecting the input data and for system problems, but
485 * DECOMP_FATALERROR for any errors which could possibly be said to
486 * be being detected "after" decompression. For DECOMP_ERROR,
487 * we can issue a CCP reset-request; for DECOMP_FATALERROR, we may be
488 * infringing a patent of Motorola's if we do, so we take CCP down
491 * Given that the frame has the correct sequence number and a good FCS,
492 * errors such as invalid codes in the input most likely indicate a
493 * bug, so we return DECOMP_FATALERROR for them in order to turn off
494 * compression, even though they are detected by inspecting the input.
497 z_decompress(arg
, mi
, mop
)
499 struct mbuf
*mi
, **mop
;
501 struct deflate_state
*state
= (struct deflate_state
*) arg
;
502 struct mbuf
*mo
, *mo_head
;
504 int rlen
, olen
, ospace
;
505 int seq
, i
, flush
, r
, decode_proto
;
506 u_char hdr
[PPP_HDRLEN
+ DEFLATE_OVHD
];
509 rptr
= mtod(mi
, u_char
*);
511 for (i
= 0; i
< PPP_HDRLEN
+ DEFLATE_OVHD
; ++i
) {
516 rptr
= mtod(mi
, u_char
*);
523 /* Check the sequence number. */
524 seq
= (hdr
[PPP_HDRLEN
] << 8) + hdr
[PPP_HDRLEN
+1];
525 if (seq
!= state
->seqno
) {
527 printf("z_decompress%d: bad seq # %d, expected %d\n",
528 state
->unit
, seq
, state
->seqno
);
533 /* Allocate an output mbuf. */
534 MGETHDR(mo
, M_DONTWAIT
, MT_DATA
);
540 MCLGET(mo
, M_DONTWAIT
);
541 ospace
= M_TRAILINGSPACE(mo
);
542 if (state
->hdrlen
+ PPP_HDRLEN
< ospace
) {
543 mo
->m_data
+= state
->hdrlen
;
544 ospace
-= state
->hdrlen
;
548 * Fill in the first part of the PPP header. The protocol field
549 * comes from the decompressed data.
551 wptr
= mtod(mo
, u_char
*);
552 wptr
[0] = PPP_ADDRESS(hdr
);
553 wptr
[1] = PPP_CONTROL(hdr
);
557 * Set up to call inflate. We set avail_out to 1 initially so we can
558 * look at the first byte of the output and decide whether we have
559 * a 1-byte or 2-byte protocol field.
561 state
->strm
.next_in
= rptr
;
562 state
->strm
.avail_in
= rlen
;
564 flush
= (mi
== NULL
)? Z_PACKET_FLUSH
: Z_NO_FLUSH
;
565 rlen
+= PPP_HDRLEN
+ DEFLATE_OVHD
;
566 state
->strm
.next_out
= wptr
+ 3;
567 state
->strm
.avail_out
= 1;
572 * Call inflate, supplying more input or output as needed.
575 r
= inflate(&state
->strm
, flush
);
580 printf("z_decompress%d: inflate returned %d (%s)\n",
581 state
->unit
, r
, (state
->strm
.msg
? state
->strm
.msg
: ""));
583 return DECOMP_FATALERROR
;
585 if (flush
!= Z_NO_FLUSH
&& state
->strm
.avail_out
!= 0)
586 break; /* all done */
587 if (state
->strm
.avail_in
== 0 && mi
!= NULL
) {
588 state
->strm
.next_in
= mtod(mi
, u_char
*);
589 state
->strm
.avail_in
= mi
->m_len
;
593 flush
= Z_PACKET_FLUSH
;
595 if (state
->strm
.avail_out
== 0) {
597 state
->strm
.avail_out
= ospace
- PPP_HDRLEN
;
598 if ((wptr
[3] & 1) == 0) {
599 /* 2-byte protocol field */
601 --state
->strm
.next_out
;
602 ++state
->strm
.avail_out
;
609 MGET(mo
->m_next
, M_DONTWAIT
, MT_DATA
);
615 MCLGET(mo
, M_DONTWAIT
);
616 state
->strm
.next_out
= mtod(mo
, u_char
*);
617 state
->strm
.avail_out
= ospace
= M_TRAILINGSPACE(mo
);
625 olen
+= (mo
->m_len
= ospace
- state
->strm
.avail_out
);
627 if (state
->debug
&& olen
> state
->mru
+ PPP_HDRLEN
)
628 printf("ppp_deflate%d: exceeded mru (%d > %d)\n",
629 state
->unit
, olen
, state
->mru
+ PPP_HDRLEN
);
632 state
->stats
.unc_bytes
+= olen
;
633 state
->stats
.unc_packets
++;
634 state
->stats
.comp_bytes
+= rlen
;
635 state
->stats
.comp_packets
++;
642 * Incompressible data has arrived - add it to the history.
649 struct deflate_state
*state
= (struct deflate_state
*) arg
;
654 * Check that the protocol is one we handle.
656 rptr
= mtod(mi
, u_char
*);
657 proto
= PPP_PROTOCOL(rptr
);
658 if (proto
> 0x3fff || proto
== 0xfd || proto
== 0xfb)
664 * Iterate through the mbufs, adding the characters in them
665 * to the decompressor's history. For the first mbuf, we start
666 * at the either the 1st or 2nd byte of the protocol field,
667 * depending on whether the protocol value is compressible.
670 state
->strm
.next_in
= rptr
+ 3;
671 state
->strm
.avail_in
= rlen
- 3;
673 --state
->strm
.next_in
;
674 ++state
->strm
.avail_in
;
677 r
= inflateIncomp(&state
->strm
);
683 printf("z_incomp%d: inflateIncomp returned %d (%s)\n",
684 state
->unit
, r
, (state
->strm
.msg
? state
->strm
.msg
: ""));
690 state
->strm
.next_in
= mtod(mi
, u_char
*);
691 state
->strm
.avail_in
= mi
->m_len
;
698 state
->stats
.inc_bytes
+= rlen
;
699 state
->stats
.inc_packets
++;
700 state
->stats
.unc_bytes
+= rlen
;
701 state
->stats
.unc_packets
++;
704 #endif /* DO_DEFLATE */