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