1/* 2 * ppp_deflate.c - interface the zlib procedures for Deflate compression 3 * and decompression (as used by gzip) to the PPP code. 4 * 5 * Copyright (c) 1994 Paul Mackerras. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in 16 * the documentation and/or other materials provided with the 17 * distribution. 18 * 19 * 3. The name(s) of the authors of this software must not be used to 20 * endorse or promote products derived from this software without 21 * prior written permission. 22 * 23 * 4. Redistributions of any form whatsoever must retain the following 24 * acknowledgment: 25 * "This product includes software developed by Paul Mackerras 26 * <paulus@samba.org>". 27 * 28 * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO 29 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 30 * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY 31 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 32 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 33 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 34 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 35 * 36 * $Id: deflate.c,v 1.5 2004/01/17 05:47:55 carlsonj Exp $ 37 */ 38 39#include <sys/types.h> 40#include <stdio.h> 41#include <stddef.h> 42#include <stdlib.h> 43#include <string.h> 44#include "ppp_defs.h" 45#include "ppp-comp.h" 46#include "zlib.h" 47 48#if DO_DEFLATE 49 50#define DEFLATE_DEBUG 1 51 52/* 53 * State for a Deflate (de)compressor. 54 */ 55struct deflate_state { 56 int seqno; 57 int w_size; 58 int unit; 59 int hdrlen; 60 int mru; 61 int debug; 62 z_stream strm; 63 struct compstat stats; 64}; 65 66#define DEFLATE_OVHD 2 /* Deflate overhead/packet */ 67 68static void *z_alloc __P((void *, u_int items, u_int size)); 69static void z_free __P((void *, void *ptr, u_int nb)); 70static void *z_decomp_alloc __P((u_char *options, int opt_len)); 71static void z_decomp_free __P((void *state)); 72static int z_decomp_init __P((void *state, u_char *options, int opt_len, 73 int unit, int hdrlen, int mru, int debug)); 74static void z_incomp __P((void *state, u_char *dmsg, int len)); 75static int z_decompress __P((void *state, u_char *cmp, int inlen, 76 u_char *dmp, int *outlenp)); 77static void z_decomp_reset __P((void *state)); 78static void z_comp_stats __P((void *state, struct compstat *stats)); 79 80/* 81 * Procedures exported to if_ppp.c. 82 */ 83struct compressor ppp_deflate = { 84 CI_DEFLATE, /* compress_proto */ 85 z_decomp_alloc, /* decomp_alloc */ 86 z_decomp_free, /* decomp_free */ 87 z_decomp_init, /* decomp_init */ 88 z_decomp_reset, /* decomp_reset */ 89 z_decompress, /* decompress */ 90 z_incomp, /* incomp */ 91 z_comp_stats, /* decomp_stat */ 92}; 93 94/* 95 * Space allocation and freeing routines for use by zlib routines. 96 */ 97static void * 98z_alloc(notused, items, size) 99 void *notused; 100 u_int items, size; 101{ 102 return malloc(items * size); 103} 104 105static void 106z_free(notused, ptr, nbytes) 107 void *notused; 108 void *ptr; 109 u_int nbytes; 110{ 111 free(ptr); 112} 113 114static void 115z_comp_stats(arg, stats) 116 void *arg; 117 struct compstat *stats; 118{ 119 struct deflate_state *state = (struct deflate_state *) arg; 120 u_int out; 121 122 *stats = state->stats; 123 stats->ratio = stats->unc_bytes; 124 out = stats->comp_bytes + stats->unc_bytes; 125 if (stats->ratio <= 0x7ffffff) 126 stats->ratio <<= 8; 127 else 128 out >>= 8; 129 if (out != 0) 130 stats->ratio /= out; 131} 132 133/* 134 * Allocate space for a decompressor. 135 */ 136static void * 137z_decomp_alloc(options, opt_len) 138 u_char *options; 139 int opt_len; 140{ 141 struct deflate_state *state; 142 int w_size; 143 144 if (opt_len != CILEN_DEFLATE || options[0] != CI_DEFLATE 145 || options[1] != CILEN_DEFLATE 146 || DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL 147 || options[3] != DEFLATE_CHK_SEQUENCE) 148 return NULL; 149 w_size = DEFLATE_SIZE(options[2]); 150 if (w_size < DEFLATE_MIN_SIZE || w_size > DEFLATE_MAX_SIZE) 151 return NULL; 152 153 state = (struct deflate_state *) malloc(sizeof(*state)); 154 if (state == NULL) 155 return NULL; 156 157 state->strm.next_out = NULL; 158 state->strm.zalloc = (alloc_func) z_alloc; 159 state->strm.zfree = (free_func) z_free; 160 if (inflateInit2(&state->strm, -w_size) != Z_OK) { 161 free(state); 162 return NULL; 163 } 164 165 state->w_size = w_size; 166 memset(&state->stats, 0, sizeof(state->stats)); 167 return (void *) state; 168} 169 170static void 171z_decomp_free(arg) 172 void *arg; 173{ 174 struct deflate_state *state = (struct deflate_state *) arg; 175 176 inflateEnd(&state->strm); 177 free(state); 178} 179 180static int 181z_decomp_init(arg, options, opt_len, unit, hdrlen, mru, debug) 182 void *arg; 183 u_char *options; 184 int opt_len, unit, hdrlen, mru, debug; 185{ 186 struct deflate_state *state = (struct deflate_state *) arg; 187 188 if (opt_len < CILEN_DEFLATE || options[0] != CI_DEFLATE 189 || options[1] != CILEN_DEFLATE 190 || DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL 191 || DEFLATE_SIZE(options[2]) != state->w_size 192 || options[3] != DEFLATE_CHK_SEQUENCE) 193 return 0; 194 195 state->seqno = 0; 196 state->unit = unit; 197 state->hdrlen = hdrlen; 198 state->debug = debug; 199 state->mru = mru; 200 201 inflateReset(&state->strm); 202 203 return 1; 204} 205 206static void 207z_decomp_reset(arg) 208 void *arg; 209{ 210 struct deflate_state *state = (struct deflate_state *) arg; 211 212 state->seqno = 0; 213 inflateReset(&state->strm); 214} 215 216/* 217 * Decompress a Deflate-compressed packet. 218 * 219 * Because of patent problems, we return DECOMP_ERROR for errors 220 * found by inspecting the input data and for system problems, but 221 * DECOMP_FATALERROR for any errors which could possibly be said to 222 * be being detected "after" decompression. For DECOMP_ERROR, 223 * we can issue a CCP reset-request; for DECOMP_FATALERROR, we may be 224 * infringing a patent of Motorola's if we do, so we take CCP down 225 * instead. 226 * 227 * Given that the frame has the correct sequence number and a good FCS, 228 * errors such as invalid codes in the input most likely indicate a 229 * bug, so we return DECOMP_FATALERROR for them in order to turn off 230 * compression, even though they are detected by inspecting the input. 231 */ 232static int 233z_decompress(arg, mi, inlen, mo, outlenp) 234 void *arg; 235 u_char *mi, *mo; 236 int inlen, *outlenp; 237{ 238 struct deflate_state *state = (struct deflate_state *) arg; 239 u_char *rptr, *wptr; 240 int rlen, olen, ospace; 241 int seq, i, flush, r, decode_proto; 242 243 rptr = mi; 244 if (*rptr == 0) 245 ++rptr; 246 ++rptr; 247 248 /* Check the sequence number. */ 249 seq = (rptr[0] << 8) + rptr[1]; 250 rptr += 2; 251 if (seq != state->seqno) { 252#if !DEFLATE_DEBUG 253 if (state->debug) 254#endif 255 printf("z_decompress%d: bad seq # %d, expected %d\n", 256 state->unit, seq, state->seqno); 257 return DECOMP_ERROR; 258 } 259 ++state->seqno; 260 261 /* 262 * Set up to call inflate. 263 */ 264 wptr = mo; 265 state->strm.next_in = rptr; 266 state->strm.avail_in = mi + inlen - rptr; 267 rlen = state->strm.avail_in + PPP_HDRLEN + DEFLATE_OVHD; 268 state->strm.next_out = wptr; 269 state->strm.avail_out = state->mru + 2; 270 271 r = inflate(&state->strm, Z_PACKET_FLUSH); 272 if (r != Z_OK) { 273#if !DEFLATE_DEBUG 274 if (state->debug) 275#endif 276 printf("z_decompress%d: inflate returned %d (%s)\n", 277 state->unit, r, (state->strm.msg? state->strm.msg: "")); 278 return DECOMP_FATALERROR; 279 } 280 olen = state->mru + 2 - state->strm.avail_out; 281 *outlenp = olen; 282 283 if ((wptr[0] & 1) != 0) 284 ++olen; /* for suppressed protocol high byte */ 285 olen += 2; /* for address, control */ 286 287#if DEFLATE_DEBUG 288 if (olen > state->mru + PPP_HDRLEN) 289 printf("ppp_deflate%d: exceeded mru (%d > %d)\n", 290 state->unit, olen, state->mru + PPP_HDRLEN); 291#endif 292 293 state->stats.unc_bytes += olen; 294 state->stats.unc_packets++; 295 state->stats.comp_bytes += rlen; 296 state->stats.comp_packets++; 297 298 return DECOMP_OK; 299} 300 301/* 302 * Incompressible data has arrived - add it to the history. 303 */ 304static void 305z_incomp(arg, mi, mlen) 306 void *arg; 307 u_char *mi; 308 int mlen; 309{ 310 struct deflate_state *state = (struct deflate_state *) arg; 311 u_char *rptr; 312 int rlen, proto, r; 313 314 /* 315 * Check that the protocol is one we handle. 316 */ 317 rptr = mi; 318 proto = rptr[0]; 319 if ((proto & 1) == 0) 320 proto = (proto << 8) + rptr[1]; 321 if (proto > 0x3fff || proto == 0xfd || proto == 0xfb) 322 return; 323 324 ++state->seqno; 325 326 if (rptr[0] == 0) 327 ++rptr; 328 rlen = mi + mlen - rptr; 329 state->strm.next_in = rptr; 330 state->strm.avail_in = rlen; 331 r = inflateIncomp(&state->strm); 332 if (r != Z_OK) { 333 /* gak! */ 334#if !DEFLATE_DEBUG 335 if (state->debug) 336#endif 337 printf("z_incomp%d: inflateIncomp returned %d (%s)\n", 338 state->unit, r, (state->strm.msg? state->strm.msg: "")); 339 return; 340 } 341 342 /* 343 * Update stats. 344 */ 345 if (proto <= 0xff) 346 ++rlen; 347 rlen += 2; 348 state->stats.inc_bytes += rlen; 349 state->stats.inc_packets++; 350 state->stats.unc_bytes += rlen; 351 state->stats.unc_packets++; 352} 353 354#endif /* DO_DEFLATE */ 355