2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
26 * ppp_deflate.c - interface the zlib procedures for Deflate compression
27 * and decompression (as used by gzip) to the PPP code.
28 * This version is for use with mbufs on BSD-derived systems.
30 * Copyright (c) 1994 The Australian National University.
31 * All rights reserved.
33 * Permission to use, copy, modify, and distribute this software and its
34 * documentation is hereby granted, provided that the above copyright
35 * notice appears in all copies. This software is provided without any
36 * warranty, express or implied. The Australian National University
37 * makes no representations about the suitability of this software for
40 * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
41 * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
42 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
43 * THE AUSTRALIAN NATIONAL UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY
46 * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
47 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
48 * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
49 * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
50 * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
54 #include <sys/param.h>
55 #include <sys/systm.h>
56 #include <sys/malloc.h>
58 #include <net/ppp_defs.h>
61 #define PACKETPTR struct mbuf *
62 #include <net/ppp_comp.h>
66 #define DEFLATE_DEBUG 1
69 * State for a Deflate (de)compressor.
71 struct deflate_state
{
79 struct compstat stats
;
82 #define DEFLATE_OVHD 2 /* Deflate overhead/packet */
84 static void *z_alloc
__P((void *, u_int items
, u_int size
));
85 static void z_free
__P((void *, void *ptr
));
86 static void *z_comp_alloc
__P((u_char
*options
, int opt_len
));
87 static void *z_decomp_alloc
__P((u_char
*options
, int opt_len
));
88 static void z_comp_free
__P((void *state
));
89 static void z_decomp_free
__P((void *state
));
90 static int z_comp_init
__P((void *state
, u_char
*options
, int opt_len
,
91 int unit
, int hdrlen
, int debug
));
92 static int z_decomp_init
__P((void *state
, u_char
*options
, int opt_len
,
93 int unit
, int hdrlen
, int mru
, int debug
));
94 static int z_compress
__P((void *state
, struct mbuf
**mret
,
95 struct mbuf
*mp
, int slen
, int maxolen
));
96 static void z_incomp
__P((void *state
, struct mbuf
*dmsg
));
97 static int z_decompress
__P((void *state
, struct mbuf
*cmp
,
99 static void z_comp_reset
__P((void *state
));
100 static void z_decomp_reset
__P((void *state
));
101 static void z_comp_stats
__P((void *state
, struct compstat
*stats
));
104 * Procedures exported to if_ppp.c.
106 struct compressor ppp_deflate
= {
107 CI_DEFLATE
, /* compress_proto */
108 z_comp_alloc
, /* comp_alloc */
109 z_comp_free
, /* comp_free */
110 z_comp_init
, /* comp_init */
111 z_comp_reset
, /* comp_reset */
112 z_compress
, /* compress */
113 z_comp_stats
, /* comp_stat */
114 z_decomp_alloc
, /* decomp_alloc */
115 z_decomp_free
, /* decomp_free */
116 z_decomp_init
, /* decomp_init */
117 z_decomp_reset
, /* decomp_reset */
118 z_decompress
, /* decompress */
119 z_incomp
, /* incomp */
120 z_comp_stats
, /* decomp_stat */
123 struct compressor ppp_deflate_draft
= {
124 CI_DEFLATE_DRAFT
, /* compress_proto */
125 z_comp_alloc
, /* comp_alloc */
126 z_comp_free
, /* comp_free */
127 z_comp_init
, /* comp_init */
128 z_comp_reset
, /* comp_reset */
129 z_compress
, /* compress */
130 z_comp_stats
, /* comp_stat */
131 z_decomp_alloc
, /* decomp_alloc */
132 z_decomp_free
, /* decomp_free */
133 z_decomp_init
, /* decomp_init */
134 z_decomp_reset
, /* decomp_reset */
135 z_decompress
, /* decompress */
136 z_incomp
, /* incomp */
137 z_comp_stats
, /* decomp_stat */
141 * Space allocation and freeing routines for use by zlib routines.
144 z_alloc(notused
, items
, size
)
150 MALLOC(ptr
, void *, items
* size
, M_DEVBUF
, M_NOWAIT
);
163 * Allocate space for a compressor.
166 z_comp_alloc(options
, opt_len
)
170 struct deflate_state
*state
;
173 if (opt_len
!= CILEN_DEFLATE
174 || (options
[0] != CI_DEFLATE
&& options
[0] != CI_DEFLATE_DRAFT
)
175 || options
[1] != CILEN_DEFLATE
176 || DEFLATE_METHOD(options
[2]) != DEFLATE_METHOD_VAL
177 || options
[3] != DEFLATE_CHK_SEQUENCE
)
179 w_size
= DEFLATE_SIZE(options
[2]);
180 if (w_size
< DEFLATE_MIN_SIZE
|| w_size
> DEFLATE_MAX_SIZE
)
183 MALLOC(state
, struct deflate_state
*, sizeof(struct deflate_state
),
188 state
->strm
.next_in
= NULL
;
189 state
->strm
.zalloc
= z_alloc
;
190 state
->strm
.zfree
= z_free
;
191 if (deflateInit2(&state
->strm
, Z_DEFAULT_COMPRESSION
, DEFLATE_METHOD_VAL
,
192 -w_size
, 8, Z_DEFAULT_STRATEGY
) != Z_OK
) {
193 FREE(state
, M_DEVBUF
);
197 state
->w_size
= w_size
;
198 bzero(&state
->stats
, sizeof(state
->stats
));
199 return (void *) state
;
206 struct deflate_state
*state
= (struct deflate_state
*) arg
;
208 deflateEnd(&state
->strm
);
209 FREE(state
, M_DEVBUF
);
213 z_comp_init(arg
, options
, opt_len
, unit
, hdrlen
, debug
)
216 int opt_len
, unit
, hdrlen
, debug
;
218 struct deflate_state
*state
= (struct deflate_state
*) arg
;
220 if (opt_len
< CILEN_DEFLATE
221 || (options
[0] != CI_DEFLATE
&& options
[0] != CI_DEFLATE_DRAFT
)
222 || options
[1] != CILEN_DEFLATE
223 || DEFLATE_METHOD(options
[2]) != DEFLATE_METHOD_VAL
224 || DEFLATE_SIZE(options
[2]) != state
->w_size
225 || options
[3] != DEFLATE_CHK_SEQUENCE
)
230 state
->hdrlen
= hdrlen
;
231 state
->debug
= debug
;
233 deflateReset(&state
->strm
);
242 struct deflate_state
*state
= (struct deflate_state
*) arg
;
245 deflateReset(&state
->strm
);
249 z_compress(arg
, mret
, mp
, orig_len
, maxolen
)
251 struct mbuf
**mret
; /* compressed packet (out) */
252 struct mbuf
*mp
; /* uncompressed packet (in) */
253 int orig_len
, maxolen
;
255 struct deflate_state
*state
= (struct deflate_state
*) arg
;
257 int proto
, olen
, wspace
, r
, flush
;
261 * Check that the protocol is in the range we handle.
263 rptr
= mtod(mp
, u_char
*);
264 proto
= PPP_PROTOCOL(rptr
);
265 if (proto
> 0x3fff || proto
== 0xfd || proto
== 0xfb) {
270 /* Allocate one mbuf initially. */
271 if (maxolen
> orig_len
)
273 MGET(m
, M_DONTWAIT
, MT_DATA
);
277 if (maxolen
+ state
->hdrlen
> MLEN
)
278 MCLGET(m
, M_DONTWAIT
);
279 wspace
= M_TRAILINGSPACE(m
);
280 if (state
->hdrlen
+ PPP_HDRLEN
+ 2 < wspace
) {
281 m
->m_data
+= state
->hdrlen
;
282 wspace
-= state
->hdrlen
;
284 wptr
= mtod(m
, u_char
*);
287 * Copy over the PPP header and store the 2-byte sequence number.
289 wptr
[0] = PPP_ADDRESS(rptr
);
290 wptr
[1] = PPP_CONTROL(rptr
);
291 wptr
[2] = PPP_COMP
>> 8;
294 wptr
[0] = state
->seqno
>> 8;
295 wptr
[1] = state
->seqno
;
297 state
->strm
.next_out
= wptr
;
298 state
->strm
.avail_out
= wspace
- (PPP_HDRLEN
+ 2);
300 state
->strm
.next_out
= NULL
;
301 state
->strm
.avail_out
= 1000000;
307 rptr
+= (proto
> 0xff)? 2: 3; /* skip 1st proto byte if 0 */
308 state
->strm
.next_in
= rptr
;
309 state
->strm
.avail_in
= mtod(mp
, u_char
*) + mp
->m_len
- rptr
;
311 flush
= (mp
== NULL
)? Z_PACKET_FLUSH
: Z_NO_FLUSH
;
314 r
= deflate(&state
->strm
, flush
);
316 printf("z_compress: deflate returned %d (%s)\n",
317 r
, (state
->strm
.msg
? state
->strm
.msg
: ""));
320 if (flush
!= Z_NO_FLUSH
&& state
->strm
.avail_out
!= 0)
321 break; /* all done */
322 if (state
->strm
.avail_in
== 0 && mp
!= NULL
) {
323 state
->strm
.next_in
= mtod(mp
, u_char
*);
324 state
->strm
.avail_in
= mp
->m_len
;
327 flush
= Z_PACKET_FLUSH
;
329 if (state
->strm
.avail_out
== 0) {
333 MGET(m
->m_next
, M_DONTWAIT
, MT_DATA
);
337 if (maxolen
- olen
> MLEN
)
338 MCLGET(m
, M_DONTWAIT
);
339 state
->strm
.next_out
= mtod(m
, u_char
*);
340 state
->strm
.avail_out
= wspace
= M_TRAILINGSPACE(m
);
344 state
->strm
.next_out
= NULL
;
345 state
->strm
.avail_out
= 1000000;
350 olen
+= (m
->m_len
= wspace
- state
->strm
.avail_out
);
353 * See if we managed to reduce the size of the packet.
355 if (m
!= NULL
&& olen
< orig_len
) {
356 state
->stats
.comp_bytes
+= olen
;
357 state
->stats
.comp_packets
++;
363 state
->stats
.inc_bytes
+= orig_len
;
364 state
->stats
.inc_packets
++;
367 state
->stats
.unc_bytes
+= orig_len
;
368 state
->stats
.unc_packets
++;
374 z_comp_stats(arg
, stats
)
376 struct compstat
*stats
;
378 struct deflate_state
*state
= (struct deflate_state
*) arg
;
381 *stats
= state
->stats
;
382 stats
->ratio
= stats
->unc_bytes
;
383 out
= stats
->comp_bytes
+ stats
->inc_bytes
;
384 if (stats
->ratio
<= 0x7ffffff)
393 * Allocate space for a decompressor.
396 z_decomp_alloc(options
, opt_len
)
400 struct deflate_state
*state
;
403 if (opt_len
!= CILEN_DEFLATE
404 || (options
[0] != CI_DEFLATE
&& options
[0] != CI_DEFLATE_DRAFT
)
405 || options
[1] != CILEN_DEFLATE
406 || DEFLATE_METHOD(options
[2]) != DEFLATE_METHOD_VAL
407 || options
[3] != DEFLATE_CHK_SEQUENCE
)
409 w_size
= DEFLATE_SIZE(options
[2]);
410 if (w_size
< DEFLATE_MIN_SIZE
|| w_size
> DEFLATE_MAX_SIZE
)
413 MALLOC(state
, struct deflate_state
*, sizeof(struct deflate_state
),
418 state
->strm
.next_out
= NULL
;
419 state
->strm
.zalloc
= z_alloc
;
420 state
->strm
.zfree
= z_free
;
421 if (inflateInit2(&state
->strm
, -w_size
) != Z_OK
) {
422 FREE(state
, M_DEVBUF
);
426 state
->w_size
= w_size
;
427 bzero(&state
->stats
, sizeof(state
->stats
));
428 return (void *) state
;
435 struct deflate_state
*state
= (struct deflate_state
*) arg
;
437 inflateEnd(&state
->strm
);
438 FREE(state
, M_DEVBUF
);
442 z_decomp_init(arg
, options
, opt_len
, unit
, hdrlen
, mru
, debug
)
445 int opt_len
, unit
, hdrlen
, mru
, debug
;
447 struct deflate_state
*state
= (struct deflate_state
*) arg
;
449 if (opt_len
< CILEN_DEFLATE
450 || (options
[0] != CI_DEFLATE
&& options
[0] != CI_DEFLATE_DRAFT
)
451 || options
[1] != CILEN_DEFLATE
452 || DEFLATE_METHOD(options
[2]) != DEFLATE_METHOD_VAL
453 || DEFLATE_SIZE(options
[2]) != state
->w_size
454 || options
[3] != DEFLATE_CHK_SEQUENCE
)
459 state
->hdrlen
= hdrlen
;
460 state
->debug
= debug
;
463 inflateReset(&state
->strm
);
472 struct deflate_state
*state
= (struct deflate_state
*) arg
;
475 inflateReset(&state
->strm
);
479 * Decompress a Deflate-compressed packet.
481 * Because of patent problems, we return DECOMP_ERROR for errors
482 * found by inspecting the input data and for system problems, but
483 * DECOMP_FATALERROR for any errors which could possibly be said to
484 * be being detected "after" decompression. For DECOMP_ERROR,
485 * we can issue a CCP reset-request; for DECOMP_FATALERROR, we may be
486 * infringing a patent of Motorola's if we do, so we take CCP down
489 * Given that the frame has the correct sequence number and a good FCS,
490 * errors such as invalid codes in the input most likely indicate a
491 * bug, so we return DECOMP_FATALERROR for them in order to turn off
492 * compression, even though they are detected by inspecting the input.
495 z_decompress(arg
, mi
, mop
)
497 struct mbuf
*mi
, **mop
;
499 struct deflate_state
*state
= (struct deflate_state
*) arg
;
500 struct mbuf
*mo
, *mo_head
;
502 int rlen
, olen
, ospace
;
503 int seq
, i
, flush
, r
, decode_proto
;
504 u_char hdr
[PPP_HDRLEN
+ DEFLATE_OVHD
];
507 rptr
= mtod(mi
, u_char
*);
509 for (i
= 0; i
< PPP_HDRLEN
+ DEFLATE_OVHD
; ++i
) {
514 rptr
= mtod(mi
, u_char
*);
521 /* Check the sequence number. */
522 seq
= (hdr
[PPP_HDRLEN
] << 8) + hdr
[PPP_HDRLEN
+1];
523 if (seq
!= state
->seqno
) {
525 printf("z_decompress%d: bad seq # %d, expected %d\n",
526 state
->unit
, seq
, state
->seqno
);
531 /* Allocate an output mbuf. */
532 MGETHDR(mo
, M_DONTWAIT
, MT_DATA
);
538 MCLGET(mo
, M_DONTWAIT
);
539 ospace
= M_TRAILINGSPACE(mo
);
540 if (state
->hdrlen
+ PPP_HDRLEN
< ospace
) {
541 mo
->m_data
+= state
->hdrlen
;
542 ospace
-= state
->hdrlen
;
546 * Fill in the first part of the PPP header. The protocol field
547 * comes from the decompressed data.
549 wptr
= mtod(mo
, u_char
*);
550 wptr
[0] = PPP_ADDRESS(hdr
);
551 wptr
[1] = PPP_CONTROL(hdr
);
555 * Set up to call inflate. We set avail_out to 1 initially so we can
556 * look at the first byte of the output and decide whether we have
557 * a 1-byte or 2-byte protocol field.
559 state
->strm
.next_in
= rptr
;
560 state
->strm
.avail_in
= rlen
;
562 flush
= (mi
== NULL
)? Z_PACKET_FLUSH
: Z_NO_FLUSH
;
563 rlen
+= PPP_HDRLEN
+ DEFLATE_OVHD
;
564 state
->strm
.next_out
= wptr
+ 3;
565 state
->strm
.avail_out
= 1;
570 * Call inflate, supplying more input or output as needed.
573 r
= inflate(&state
->strm
, flush
);
578 printf("z_decompress%d: inflate returned %d (%s)\n",
579 state
->unit
, r
, (state
->strm
.msg
? state
->strm
.msg
: ""));
581 return DECOMP_FATALERROR
;
583 if (flush
!= Z_NO_FLUSH
&& state
->strm
.avail_out
!= 0)
584 break; /* all done */
585 if (state
->strm
.avail_in
== 0 && mi
!= NULL
) {
586 state
->strm
.next_in
= mtod(mi
, u_char
*);
587 state
->strm
.avail_in
= mi
->m_len
;
591 flush
= Z_PACKET_FLUSH
;
593 if (state
->strm
.avail_out
== 0) {
595 state
->strm
.avail_out
= ospace
- PPP_HDRLEN
;
596 if ((wptr
[3] & 1) == 0) {
597 /* 2-byte protocol field */
599 --state
->strm
.next_out
;
600 ++state
->strm
.avail_out
;
607 MGET(mo
->m_next
, M_DONTWAIT
, MT_DATA
);
613 MCLGET(mo
, M_DONTWAIT
);
614 state
->strm
.next_out
= mtod(mo
, u_char
*);
615 state
->strm
.avail_out
= ospace
= M_TRAILINGSPACE(mo
);
623 olen
+= (mo
->m_len
= ospace
- state
->strm
.avail_out
);
625 if (state
->debug
&& olen
> state
->mru
+ PPP_HDRLEN
)
626 printf("ppp_deflate%d: exceeded mru (%d > %d)\n",
627 state
->unit
, olen
, state
->mru
+ PPP_HDRLEN
);
630 state
->stats
.unc_bytes
+= olen
;
631 state
->stats
.unc_packets
++;
632 state
->stats
.comp_bytes
+= rlen
;
633 state
->stats
.comp_packets
++;
640 * Incompressible data has arrived - add it to the history.
647 struct deflate_state
*state
= (struct deflate_state
*) arg
;
652 * Check that the protocol is one we handle.
654 rptr
= mtod(mi
, u_char
*);
655 proto
= PPP_PROTOCOL(rptr
);
656 if (proto
> 0x3fff || proto
== 0xfd || proto
== 0xfb)
662 * Iterate through the mbufs, adding the characters in them
663 * to the decompressor's history. For the first mbuf, we start
664 * at the either the 1st or 2nd byte of the protocol field,
665 * depending on whether the protocol value is compressible.
668 state
->strm
.next_in
= rptr
+ 3;
669 state
->strm
.avail_in
= rlen
- 3;
671 --state
->strm
.next_in
;
672 ++state
->strm
.avail_in
;
675 r
= inflateIncomp(&state
->strm
);
681 printf("z_incomp%d: inflateIncomp returned %d (%s)\n",
682 state
->unit
, r
, (state
->strm
.msg
? state
->strm
.msg
: ""));
688 state
->strm
.next_in
= mtod(mi
, u_char
*);
689 state
->strm
.avail_in
= mi
->m_len
;
696 state
->stats
.inc_bytes
+= rlen
;
697 state
->stats
.inc_packets
++;
698 state
->stats
.unc_bytes
+= rlen
;
699 state
->stats
.unc_packets
++;
702 #endif /* DO_DEFLATE */