1/* 2 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 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. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23/* 24 * ppp_deflate.c - interface the zlib procedures for Deflate compression 25 * and decompression (as used by gzip) to the PPP code. 26 * 27 * Copyright (c) 1994 The Australian National University. 28 * All rights reserved. 29 * 30 * Permission to use, copy, modify, and distribute this software and its 31 * documentation is hereby granted, provided that the above copyright 32 * notice appears in all copies. This software is provided without any 33 * warranty, express or implied. The Australian National University 34 * makes no representations about the suitability of this software for 35 * any purpose. 36 * 37 * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY 38 * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 39 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 40 * THE AUSTRALIAN NATIONAL UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY 41 * OF SUCH DAMAGE. 42 * 43 * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES, 44 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 45 * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 46 * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO 47 * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, 48 * OR MODIFICATIONS. 49 * 50 * $Id: deflate.c,v 1.3 2003/08/14 00:00:39 callie Exp $ 51 */ 52 53#include <sys/types.h> 54#include <stddef.h> 55#include <stdlib.h> 56#include "ppp_defs.h" 57#include "ppp-comp.h" 58#include "zlib.h" 59 60#if DO_DEFLATE 61 62#define DEFLATE_DEBUG 1 63 64/* 65 * State for a Deflate (de)compressor. 66 */ 67struct deflate_state { 68 int seqno; 69 int w_size; 70 int unit; 71 int hdrlen; 72 int mru; 73 int debug; 74 z_stream strm; 75 struct compstat stats; 76}; 77 78#define DEFLATE_OVHD 2 /* Deflate overhead/packet */ 79 80static void *z_alloc __P((void *, u_int items, u_int size)); 81static void z_free __P((void *, void *ptr, u_int nb)); 82static void *z_decomp_alloc __P((u_char *options, int opt_len)); 83static void z_decomp_free __P((void *state)); 84static int z_decomp_init __P((void *state, u_char *options, int opt_len, 85 int unit, int hdrlen, int mru, int debug)); 86static void z_incomp __P((void *state, u_char *dmsg, int len)); 87static int z_decompress __P((void *state, u_char *cmp, int inlen, 88 u_char *dmp, int *outlenp)); 89static void z_decomp_reset __P((void *state)); 90static void z_comp_stats __P((void *state, struct compstat *stats)); 91 92/* 93 * Procedures exported to if_ppp.c. 94 */ 95struct compressor ppp_deflate = { 96 CI_DEFLATE, /* compress_proto */ 97 z_decomp_alloc, /* decomp_alloc */ 98 z_decomp_free, /* decomp_free */ 99 z_decomp_init, /* decomp_init */ 100 z_decomp_reset, /* decomp_reset */ 101 z_decompress, /* decompress */ 102 z_incomp, /* incomp */ 103 z_comp_stats, /* decomp_stat */ 104}; 105 106/* 107 * Space allocation and freeing routines for use by zlib routines. 108 */ 109static void * 110z_alloc(notused, items, size) 111 void *notused; 112 u_int items, size; 113{ 114 return malloc(items * size); 115} 116 117static void 118z_free(notused, ptr, nbytes) 119 void *notused; 120 void *ptr; 121 u_int nbytes; 122{ 123 free(ptr); 124} 125 126static void 127z_comp_stats(arg, stats) 128 void *arg; 129 struct compstat *stats; 130{ 131 struct deflate_state *state = (struct deflate_state *) arg; 132 u_int out; 133 134 *stats = state->stats; 135 stats->ratio = stats->unc_bytes; 136 out = stats->comp_bytes + stats->unc_bytes; 137 if (stats->ratio <= 0x7ffffff) 138 stats->ratio <<= 8; 139 else 140 out >>= 8; 141 if (out != 0) 142 stats->ratio /= out; 143} 144 145/* 146 * Allocate space for a decompressor. 147 */ 148static void * 149z_decomp_alloc(options, opt_len) 150 u_char *options; 151 int opt_len; 152{ 153 struct deflate_state *state; 154 int w_size; 155 156 if (opt_len != CILEN_DEFLATE || options[0] != CI_DEFLATE 157 || options[1] != CILEN_DEFLATE 158 || DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL 159 || options[3] != DEFLATE_CHK_SEQUENCE) 160 return NULL; 161 w_size = DEFLATE_SIZE(options[2]); 162 if (w_size < DEFLATE_MIN_SIZE || w_size > DEFLATE_MAX_SIZE) 163 return NULL; 164 165 state = (struct deflate_state *) malloc(sizeof(*state)); 166 if (state == NULL) 167 return NULL; 168 169 state->strm.next_out = NULL; 170 state->strm.zalloc = (alloc_func) z_alloc; 171 state->strm.zfree = (free_func) z_free; 172 if (inflateInit2(&state->strm, -w_size) != Z_OK) { 173 free(state); 174 return NULL; 175 } 176 177 state->w_size = w_size; 178 memset(&state->stats, 0, sizeof(state->stats)); 179 return (void *) state; 180} 181 182static void 183z_decomp_free(arg) 184 void *arg; 185{ 186 struct deflate_state *state = (struct deflate_state *) arg; 187 188 inflateEnd(&state->strm); 189 free(state); 190} 191 192static int 193z_decomp_init(arg, options, opt_len, unit, hdrlen, mru, debug) 194 void *arg; 195 u_char *options; 196 int opt_len, unit, hdrlen, mru, debug; 197{ 198 struct deflate_state *state = (struct deflate_state *) arg; 199 200 if (opt_len < CILEN_DEFLATE || options[0] != CI_DEFLATE 201 || options[1] != CILEN_DEFLATE 202 || DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL 203 || DEFLATE_SIZE(options[2]) != state->w_size 204 || options[3] != DEFLATE_CHK_SEQUENCE) 205 return 0; 206 207 state->seqno = 0; 208 state->unit = unit; 209 state->hdrlen = hdrlen; 210 state->debug = debug; 211 state->mru = mru; 212 213 inflateReset(&state->strm); 214 215 return 1; 216} 217 218static void 219z_decomp_reset(arg) 220 void *arg; 221{ 222 struct deflate_state *state = (struct deflate_state *) arg; 223 224 state->seqno = 0; 225 inflateReset(&state->strm); 226} 227 228/* 229 * Decompress a Deflate-compressed packet. 230 * 231 * Because of patent problems, we return DECOMP_ERROR for errors 232 * found by inspecting the input data and for system problems, but 233 * DECOMP_FATALERROR for any errors which could possibly be said to 234 * be being detected "after" decompression. For DECOMP_ERROR, 235 * we can issue a CCP reset-request; for DECOMP_FATALERROR, we may be 236 * infringing a patent of Motorola's if we do, so we take CCP down 237 * instead. 238 * 239 * Given that the frame has the correct sequence number and a good FCS, 240 * errors such as invalid codes in the input most likely indicate a 241 * bug, so we return DECOMP_FATALERROR for them in order to turn off 242 * compression, even though they are detected by inspecting the input. 243 */ 244static int 245z_decompress(arg, mi, inlen, mo, outlenp) 246 void *arg; 247 u_char *mi, *mo; 248 int inlen, *outlenp; 249{ 250 struct deflate_state *state = (struct deflate_state *) arg; 251 u_char *rptr, *wptr; 252 int rlen, olen, ospace; 253 int seq, i, flush, r, decode_proto; 254 255 rptr = mi; 256 if (*rptr == 0) 257 ++rptr; 258 ++rptr; 259 260 /* Check the sequence number. */ 261 seq = (rptr[0] << 8) + rptr[1]; 262 rptr += 2; 263 if (seq != state->seqno) { 264#if !DEFLATE_DEBUG 265 if (state->debug) 266#endif 267 printf("z_decompress%d: bad seq # %d, expected %d\n", 268 state->unit, seq, state->seqno); 269 return DECOMP_ERROR; 270 } 271 ++state->seqno; 272 273 /* 274 * Set up to call inflate. 275 */ 276 wptr = mo; 277 state->strm.next_in = rptr; 278 state->strm.avail_in = mi + inlen - rptr; 279 rlen = state->strm.avail_in + PPP_HDRLEN + DEFLATE_OVHD; 280 state->strm.next_out = wptr; 281 state->strm.avail_out = state->mru + 2; 282 283 r = inflate(&state->strm, Z_PACKET_FLUSH); 284 if (r != Z_OK) { 285#if !DEFLATE_DEBUG 286 if (state->debug) 287#endif 288 printf("z_decompress%d: inflate returned %d (%s)\n", 289 state->unit, r, (state->strm.msg? state->strm.msg: "")); 290 return DECOMP_FATALERROR; 291 } 292 olen = state->mru + 2 - state->strm.avail_out; 293 *outlenp = olen; 294 295 if ((wptr[0] & 1) != 0) 296 ++olen; /* for suppressed protocol high byte */ 297 olen += 2; /* for address, control */ 298 299#if DEFLATE_DEBUG 300 if (olen > state->mru + PPP_HDRLEN) 301 printf("ppp_deflate%d: exceeded mru (%d > %d)\n", 302 state->unit, olen, state->mru + PPP_HDRLEN); 303#endif 304 305 state->stats.unc_bytes += olen; 306 state->stats.unc_packets++; 307 state->stats.comp_bytes += rlen; 308 state->stats.comp_packets++; 309 310 return DECOMP_OK; 311} 312 313/* 314 * Incompressible data has arrived - add it to the history. 315 */ 316static void 317z_incomp(arg, mi, mlen) 318 void *arg; 319 u_char *mi; 320 int mlen; 321{ 322 struct deflate_state *state = (struct deflate_state *) arg; 323 u_char *rptr; 324 int rlen, proto, r; 325 326 /* 327 * Check that the protocol is one we handle. 328 */ 329 rptr = mi; 330 proto = rptr[0]; 331 if ((proto & 1) == 0) 332 proto = (proto << 8) + rptr[1]; 333 if (proto > 0x3fff || proto == 0xfd || proto == 0xfb) 334 return; 335 336 ++state->seqno; 337 338 if (rptr[0] == 0) 339 ++rptr; 340 rlen = mi + mlen - rptr; 341 state->strm.next_in = rptr; 342 state->strm.avail_in = rlen; 343 r = inflateIncomp(&state->strm); 344 if (r != Z_OK) { 345 /* gak! */ 346#if !DEFLATE_DEBUG 347 if (state->debug) 348#endif 349 printf("z_incomp%d: inflateIncomp returned %d (%s)\n", 350 state->unit, r, (state->strm.msg? state->strm.msg: "")); 351 return; 352 } 353 354 /* 355 * Update stats. 356 */ 357 if (proto <= 0xff) 358 ++rlen; 359 rlen += 2; 360 state->stats.inc_bytes += rlen; 361 state->stats.inc_packets++; 362 state->stats.unc_bytes += rlen; 363 state->stats.unc_packets++; 364} 365 366#endif /* DO_DEFLATE */ 367