2 * Copyright (c) 2000-2007 Apple 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 * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce
58 * support for mandatory and extensible security protections. This notice
59 * is included in support of clause 2.2 (b) of the Apple Public License,
63 #include <sys/param.h>
64 #include <sys/systm.h>
65 #include <sys/malloc.h>
67 #include <net/ppp_defs.h>
68 #include <libkern/zlib.h>
70 #define PACKETPTR struct mbuf *
71 #include <net/ppp_comp.h>
74 #include <security/mac_framework.h>
79 #define DEFLATE_DEBUG 1
82 * State for a Deflate (de)compressor.
84 struct deflate_state
{
92 struct compstat stats
;
95 #define DEFLATE_OVHD 2 /* Deflate overhead/packet */
97 static void *z_alloc(void *, u_int items
, u_int size
);
98 static void z_free(void *, void *ptr
);
99 static void *z_comp_alloc(u_char
*options
, int opt_len
);
100 static void *z_decomp_alloc(u_char
*options
, int opt_len
);
101 static void z_comp_free(void *state
);
102 static void z_decomp_free(void *state
);
103 static int z_comp_init(void *state
, u_char
*options
, int opt_len
,
104 int unit
, int hdrlen
, int debug
);
105 static int z_decomp_init(void *state
, u_char
*options
, int opt_len
,
106 int unit
, int hdrlen
, int mru
, int debug
);
107 static int z_compress(void *state
, struct mbuf
**mret
,
108 struct mbuf
*mp
, int slen
, int maxolen
);
109 static void z_incomp(void *state
, struct mbuf
*dmsg
);
110 static int z_decompress(void *state
, struct mbuf
*cmp
, struct mbuf
**dmpp
);
111 static void z_comp_reset(void *state
);
112 static void z_decomp_reset(void *state
);
113 static void z_comp_stats(void *state
, struct compstat
*stats
);
116 * Procedures exported to if_ppp.c.
118 struct compressor ppp_deflate
= {
119 CI_DEFLATE
, /* compress_proto */
120 z_comp_alloc
, /* comp_alloc */
121 z_comp_free
, /* comp_free */
122 z_comp_init
, /* comp_init */
123 z_comp_reset
, /* comp_reset */
124 z_compress
, /* compress */
125 z_comp_stats
, /* comp_stat */
126 z_decomp_alloc
, /* decomp_alloc */
127 z_decomp_free
, /* decomp_free */
128 z_decomp_init
, /* decomp_init */
129 z_decomp_reset
, /* decomp_reset */
130 z_decompress
, /* decompress */
131 z_incomp
, /* incomp */
132 z_comp_stats
, /* decomp_stat */
135 struct compressor ppp_deflate_draft
= {
136 CI_DEFLATE_DRAFT
, /* compress_proto */
137 z_comp_alloc
, /* comp_alloc */
138 z_comp_free
, /* comp_free */
139 z_comp_init
, /* comp_init */
140 z_comp_reset
, /* comp_reset */
141 z_compress
, /* compress */
142 z_comp_stats
, /* comp_stat */
143 z_decomp_alloc
, /* decomp_alloc */
144 z_decomp_free
, /* decomp_free */
145 z_decomp_init
, /* decomp_init */
146 z_decomp_reset
, /* decomp_reset */
147 z_decompress
, /* decompress */
148 z_incomp
, /* incomp */
149 z_comp_stats
, /* decomp_stat */
153 * Space allocation and freeing routines for use by zlib routines.
156 z_alloc(notused
, items
, size
)
162 MALLOC(ptr
, void *, items
* size
, M_DEVBUF
, M_NOWAIT
);
175 * Allocate space for a compressor.
178 z_comp_alloc(options
, opt_len
)
182 struct deflate_state
*state
;
185 if (opt_len
!= CILEN_DEFLATE
186 || (options
[0] != CI_DEFLATE
&& options
[0] != CI_DEFLATE_DRAFT
)
187 || options
[1] != CILEN_DEFLATE
188 || DEFLATE_METHOD(options
[2]) != DEFLATE_METHOD_VAL
189 || options
[3] != DEFLATE_CHK_SEQUENCE
)
191 w_size
= DEFLATE_SIZE(options
[2]);
192 if (w_size
< DEFLATE_MIN_SIZE
|| w_size
> DEFLATE_MAX_SIZE
)
195 MALLOC(state
, struct deflate_state
*, sizeof(struct deflate_state
),
200 state
->strm
.next_in
= NULL
;
201 state
->strm
.zalloc
= z_alloc
;
202 state
->strm
.zfree
= z_free
;
203 if (deflateInit2(&state
->strm
, Z_DEFAULT_COMPRESSION
, DEFLATE_METHOD_VAL
,
204 -w_size
, 8, Z_DEFAULT_STRATEGY
) != Z_OK
) {
205 FREE(state
, M_DEVBUF
);
209 state
->w_size
= w_size
;
210 bzero(&state
->stats
, sizeof(state
->stats
));
211 return (void *) state
;
218 struct deflate_state
*state
= (struct deflate_state
*) arg
;
220 deflateEnd(&state
->strm
);
221 FREE(state
, M_DEVBUF
);
225 z_comp_init(arg
, options
, opt_len
, unit
, hdrlen
, debug
)
228 int opt_len
, unit
, hdrlen
, debug
;
230 struct deflate_state
*state
= (struct deflate_state
*) arg
;
232 if (opt_len
< CILEN_DEFLATE
233 || (options
[0] != CI_DEFLATE
&& options
[0] != CI_DEFLATE_DRAFT
)
234 || options
[1] != CILEN_DEFLATE
235 || DEFLATE_METHOD(options
[2]) != DEFLATE_METHOD_VAL
236 || DEFLATE_SIZE(options
[2]) != state
->w_size
237 || options
[3] != DEFLATE_CHK_SEQUENCE
)
242 state
->hdrlen
= hdrlen
;
243 state
->debug
= debug
;
245 deflateReset(&state
->strm
);
254 struct deflate_state
*state
= (struct deflate_state
*) arg
;
257 deflateReset(&state
->strm
);
261 z_compress(arg
, mret
, mp
, orig_len
, maxolen
)
263 struct mbuf
**mret
; /* compressed packet (out) */
264 struct mbuf
*mp
; /* uncompressed packet (in) */
265 int orig_len
, maxolen
;
267 struct deflate_state
*state
= (struct deflate_state
*) arg
;
269 int proto
, olen
, wspace
, r
, flush
;
273 * Check that the protocol is in the range we handle.
275 rptr
= mtod(mp
, u_char
*);
276 proto
= PPP_PROTOCOL(rptr
);
277 if (proto
> 0x3fff || proto
== 0xfd || proto
== 0xfb) {
282 /* Allocate one mbuf initially. */
283 if (maxolen
> orig_len
)
285 MGET(m
, M_DONTWAIT
, MT_DATA
);
289 if (maxolen
+ state
->hdrlen
> MLEN
)
290 MCLGET(m
, M_DONTWAIT
);
291 wspace
= M_TRAILINGSPACE(m
);
292 if (state
->hdrlen
+ PPP_HDRLEN
+ 2 < wspace
) {
293 m
->m_data
+= state
->hdrlen
;
294 wspace
-= state
->hdrlen
;
296 wptr
= mtod(m
, u_char
*);
299 * Copy over the PPP header and store the 2-byte sequence number.
301 wptr
[0] = PPP_ADDRESS(rptr
);
302 wptr
[1] = PPP_CONTROL(rptr
);
303 wptr
[2] = PPP_COMP
>> 8;
306 wptr
[0] = state
->seqno
>> 8;
307 wptr
[1] = state
->seqno
;
309 state
->strm
.next_out
= wptr
;
310 state
->strm
.avail_out
= wspace
- (PPP_HDRLEN
+ 2);
312 state
->strm
.next_out
= NULL
;
313 state
->strm
.avail_out
= 1000000;
319 rptr
+= (proto
> 0xff)? 2: 3; /* skip 1st proto byte if 0 */
320 state
->strm
.next_in
= rptr
;
321 state
->strm
.avail_in
= mtod(mp
, u_char
*) + mp
->m_len
- rptr
;
323 flush
= (mp
== NULL
)? Z_PACKET_FLUSH
: Z_NO_FLUSH
;
326 r
= deflate(&state
->strm
, flush
);
328 printf("z_compress: deflate returned %d (%s)\n",
329 r
, (state
->strm
.msg
? state
->strm
.msg
: ""));
332 if (flush
!= Z_NO_FLUSH
&& state
->strm
.avail_out
!= 0)
333 break; /* all done */
334 if (state
->strm
.avail_in
== 0 && mp
!= NULL
) {
335 state
->strm
.next_in
= mtod(mp
, u_char
*);
336 state
->strm
.avail_in
= mp
->m_len
;
339 flush
= Z_PACKET_FLUSH
;
341 if (state
->strm
.avail_out
== 0) {
345 MGET(m
->m_next
, M_DONTWAIT
, MT_DATA
);
349 if (maxolen
- olen
> MLEN
)
350 MCLGET(m
, M_DONTWAIT
);
351 state
->strm
.next_out
= mtod(m
, u_char
*);
352 state
->strm
.avail_out
= wspace
= M_TRAILINGSPACE(m
);
356 state
->strm
.next_out
= NULL
;
357 state
->strm
.avail_out
= 1000000;
362 olen
+= (m
->m_len
= wspace
- state
->strm
.avail_out
);
365 * See if we managed to reduce the size of the packet.
367 if (m
!= NULL
&& olen
< orig_len
) {
368 state
->stats
.comp_bytes
+= olen
;
369 state
->stats
.comp_packets
++;
375 state
->stats
.inc_bytes
+= orig_len
;
376 state
->stats
.inc_packets
++;
379 state
->stats
.unc_bytes
+= orig_len
;
380 state
->stats
.unc_packets
++;
386 z_comp_stats(arg
, stats
)
388 struct compstat
*stats
;
390 struct deflate_state
*state
= (struct deflate_state
*) arg
;
393 *stats
= state
->stats
;
394 stats
->ratio
= stats
->unc_bytes
;
395 out
= stats
->comp_bytes
+ stats
->inc_bytes
;
396 if (stats
->ratio
<= 0x7ffffff)
405 * Allocate space for a decompressor.
408 z_decomp_alloc(options
, opt_len
)
412 struct deflate_state
*state
;
415 if (opt_len
!= CILEN_DEFLATE
416 || (options
[0] != CI_DEFLATE
&& options
[0] != CI_DEFLATE_DRAFT
)
417 || options
[1] != CILEN_DEFLATE
418 || DEFLATE_METHOD(options
[2]) != DEFLATE_METHOD_VAL
419 || options
[3] != DEFLATE_CHK_SEQUENCE
)
421 w_size
= DEFLATE_SIZE(options
[2]);
422 if (w_size
< DEFLATE_MIN_SIZE
|| w_size
> DEFLATE_MAX_SIZE
)
425 MALLOC(state
, struct deflate_state
*, sizeof(struct deflate_state
),
430 state
->strm
.next_out
= NULL
;
431 state
->strm
.zalloc
= z_alloc
;
432 state
->strm
.zfree
= z_free
;
433 if (inflateInit2(&state
->strm
, -w_size
) != Z_OK
) {
434 FREE(state
, M_DEVBUF
);
438 state
->w_size
= w_size
;
439 bzero(&state
->stats
, sizeof(state
->stats
));
440 return (void *) state
;
447 struct deflate_state
*state
= (struct deflate_state
*) arg
;
449 inflateEnd(&state
->strm
);
450 FREE(state
, M_DEVBUF
);
454 z_decomp_init(arg
, options
, opt_len
, unit
, hdrlen
, mru
, debug
)
457 int opt_len
, unit
, hdrlen
, mru
, debug
;
459 struct deflate_state
*state
= (struct deflate_state
*) arg
;
461 if (opt_len
< CILEN_DEFLATE
462 || (options
[0] != CI_DEFLATE
&& options
[0] != CI_DEFLATE_DRAFT
)
463 || options
[1] != CILEN_DEFLATE
464 || DEFLATE_METHOD(options
[2]) != DEFLATE_METHOD_VAL
465 || DEFLATE_SIZE(options
[2]) != state
->w_size
466 || options
[3] != DEFLATE_CHK_SEQUENCE
)
471 state
->hdrlen
= hdrlen
;
472 state
->debug
= debug
;
475 inflateReset(&state
->strm
);
484 struct deflate_state
*state
= (struct deflate_state
*) arg
;
487 inflateReset(&state
->strm
);
491 * Decompress a Deflate-compressed packet.
493 * Because of patent problems, we return DECOMP_ERROR for errors
494 * found by inspecting the input data and for system problems, but
495 * DECOMP_FATALERROR for any errors which could possibly be said to
496 * be being detected "after" decompression. For DECOMP_ERROR,
497 * we can issue a CCP reset-request; for DECOMP_FATALERROR, we may be
498 * infringing a patent of Motorola's if we do, so we take CCP down
501 * Given that the frame has the correct sequence number and a good FCS,
502 * errors such as invalid codes in the input most likely indicate a
503 * bug, so we return DECOMP_FATALERROR for them in order to turn off
504 * compression, even though they are detected by inspecting the input.
507 z_decompress(arg
, mi
, mop
)
509 struct mbuf
*mi
, **mop
;
511 struct deflate_state
*state
= (struct deflate_state
*) arg
;
512 struct mbuf
*mo
, *mo_head
;
514 int rlen
, olen
, ospace
;
515 int seq
, i
, flush
, r
, decode_proto
;
516 u_char hdr
[PPP_HDRLEN
+ DEFLATE_OVHD
];
519 rptr
= mtod(mi
, u_char
*);
521 for (i
= 0; i
< PPP_HDRLEN
+ DEFLATE_OVHD
; ++i
) {
526 rptr
= mtod(mi
, u_char
*);
533 /* Check the sequence number. */
534 seq
= (hdr
[PPP_HDRLEN
] << 8) + hdr
[PPP_HDRLEN
+1];
535 if (seq
!= state
->seqno
) {
537 printf("z_decompress%d: bad seq # %d, expected %d\n",
538 state
->unit
, seq
, state
->seqno
);
543 /* Allocate an output mbuf. */
544 MGETHDR(mo
, M_DONTWAIT
, MT_DATA
);
550 MCLGET(mo
, M_DONTWAIT
);
551 ospace
= M_TRAILINGSPACE(mo
);
552 if (state
->hdrlen
+ PPP_HDRLEN
< ospace
) {
553 mo
->m_data
+= state
->hdrlen
;
554 ospace
-= state
->hdrlen
;
557 mac_mbuf_label_copy(mi
, mo
);
561 * Fill in the first part of the PPP header. The protocol field
562 * comes from the decompressed data.
564 wptr
= mtod(mo
, u_char
*);
565 wptr
[0] = PPP_ADDRESS(hdr
);
566 wptr
[1] = PPP_CONTROL(hdr
);
570 * Set up to call inflate. We set avail_out to 1 initially so we can
571 * look at the first byte of the output and decide whether we have
572 * a 1-byte or 2-byte protocol field.
574 state
->strm
.next_in
= rptr
;
575 state
->strm
.avail_in
= rlen
;
577 flush
= (mi
== NULL
)? Z_PACKET_FLUSH
: Z_NO_FLUSH
;
578 rlen
+= PPP_HDRLEN
+ DEFLATE_OVHD
;
579 state
->strm
.next_out
= wptr
+ 3;
580 state
->strm
.avail_out
= 1;
585 * Call inflate, supplying more input or output as needed.
588 r
= inflate(&state
->strm
, flush
);
593 printf("z_decompress%d: inflate returned %d (%s)\n",
594 state
->unit
, r
, (state
->strm
.msg
? state
->strm
.msg
: ""));
596 return DECOMP_FATALERROR
;
598 if (flush
!= Z_NO_FLUSH
&& state
->strm
.avail_out
!= 0)
599 break; /* all done */
600 if (state
->strm
.avail_in
== 0 && mi
!= NULL
) {
601 state
->strm
.next_in
= mtod(mi
, u_char
*);
602 state
->strm
.avail_in
= mi
->m_len
;
606 flush
= Z_PACKET_FLUSH
;
608 if (state
->strm
.avail_out
== 0) {
610 state
->strm
.avail_out
= ospace
- PPP_HDRLEN
;
611 if ((wptr
[3] & 1) == 0) {
612 /* 2-byte protocol field */
614 --state
->strm
.next_out
;
615 ++state
->strm
.avail_out
;
622 MGET(mo
->m_next
, M_DONTWAIT
, MT_DATA
);
628 MCLGET(mo
, M_DONTWAIT
);
629 state
->strm
.next_out
= mtod(mo
, u_char
*);
630 state
->strm
.avail_out
= ospace
= M_TRAILINGSPACE(mo
);
638 olen
+= (mo
->m_len
= ospace
- state
->strm
.avail_out
);
640 if (state
->debug
&& olen
> state
->mru
+ PPP_HDRLEN
)
641 printf("ppp_deflate%d: exceeded mru (%d > %d)\n",
642 state
->unit
, olen
, state
->mru
+ PPP_HDRLEN
);
645 state
->stats
.unc_bytes
+= olen
;
646 state
->stats
.unc_packets
++;
647 state
->stats
.comp_bytes
+= rlen
;
648 state
->stats
.comp_packets
++;
655 * Incompressible data has arrived - add it to the history.
662 struct deflate_state
*state
= (struct deflate_state
*) arg
;
667 * Check that the protocol is one we handle.
669 rptr
= mtod(mi
, u_char
*);
670 proto
= PPP_PROTOCOL(rptr
);
671 if (proto
> 0x3fff || proto
== 0xfd || proto
== 0xfb)
677 * Iterate through the mbufs, adding the characters in them
678 * to the decompressor's history. For the first mbuf, we start
679 * at the either the 1st or 2nd byte of the protocol field,
680 * depending on whether the protocol value is compressible.
683 state
->strm
.next_in
= rptr
+ 3;
684 state
->strm
.avail_in
= rlen
- 3;
686 --state
->strm
.next_in
;
687 ++state
->strm
.avail_in
;
690 r
= inflateIncomp(&state
->strm
);
696 printf("z_incomp%d: inflateIncomp returned %d (%s)\n",
697 state
->unit
, r
, (state
->strm
.msg
? state
->strm
.msg
: ""));
703 state
->strm
.next_in
= mtod(mi
, u_char
*);
704 state
->strm
.avail_in
= mi
->m_len
;
711 state
->stats
.inc_bytes
+= rlen
;
712 state
->stats
.inc_packets
++;
713 state
->stats
.unc_bytes
+= rlen
;
714 state
->stats
.unc_packets
++;
717 #endif /* DO_DEFLATE */