1 1.24 rin /* $NetBSD: ppp-deflate.c,v 1.24 2024/07/05 04:31:53 rin Exp $ */ 2 1.4 christos /* Id: ppp-deflate.c,v 1.5 1997/03/04 03:33:28 paulus Exp */ 3 1.1 paulus 4 1.1 paulus /* 5 1.1 paulus * ppp_deflate.c - interface the zlib procedures for Deflate compression 6 1.1 paulus * and decompression (as used by gzip) to the PPP code. 7 1.1 paulus * This version is for use with mbufs on BSD-derived systems. 8 1.1 paulus * 9 1.12 itojun * Copyright (c) 1989-2002 Paul Mackerras. All rights reserved. 10 1.1 paulus * 11 1.12 itojun * Redistribution and use in source and binary forms, with or without 12 1.12 itojun * modification, are permitted provided that the following conditions 13 1.12 itojun * are met: 14 1.12 itojun * 15 1.12 itojun * 1. Redistributions of source code must retain the above copyright 16 1.12 itojun * notice, this list of conditions and the following disclaimer. 17 1.12 itojun * 18 1.12 itojun * 2. Redistributions in binary form must reproduce the above copyright 19 1.12 itojun * notice, this list of conditions and the following disclaimer in 20 1.12 itojun * the documentation and/or other materials provided with the 21 1.12 itojun * distribution. 22 1.12 itojun * 23 1.12 itojun * 3. The name(s) of the authors of this software must not be used to 24 1.12 itojun * endorse or promote products derived from this software without 25 1.12 itojun * prior written permission. 26 1.12 itojun * 27 1.12 itojun * 4. Redistributions of any form whatsoever must retain the following 28 1.12 itojun * acknowledgment: 29 1.12 itojun * "This product includes software developed by Paul Mackerras 30 1.12 itojun * <paulus (at) samba.org>". 31 1.12 itojun * 32 1.12 itojun * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO 33 1.12 itojun * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 34 1.12 itojun * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY 35 1.12 itojun * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 36 1.12 itojun * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 37 1.12 itojun * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 38 1.12 itojun * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 39 1.1 paulus */ 40 1.9 lukem 41 1.9 lukem #include <sys/cdefs.h> 42 1.24 rin __KERNEL_RCSID(0, "$NetBSD: ppp-deflate.c,v 1.24 2024/07/05 04:31:53 rin Exp $"); 43 1.1 paulus 44 1.1 paulus #include <sys/param.h> 45 1.1 paulus #include <sys/systm.h> 46 1.1 paulus #include <sys/mbuf.h> 47 1.18 cube #include <sys/module.h> 48 1.18 cube #include <net/if.h> 49 1.1 paulus #include <net/ppp_defs.h> 50 1.18 cube #include <net/if_ppp.h> 51 1.17 ad #include <net/zlib.h> 52 1.1 paulus 53 1.1 paulus #define PACKETPTR struct mbuf * 54 1.1 paulus #include <net/ppp-comp.h> 55 1.1 paulus 56 1.1 paulus #if DO_DEFLATE 57 1.1 paulus 58 1.4 christos #define DEFLATE_DEBUG 1 59 1.4 christos 60 1.1 paulus /* 61 1.1 paulus * State for a Deflate (de)compressor. 62 1.1 paulus */ 63 1.1 paulus struct deflate_state { 64 1.1 paulus int seqno; 65 1.1 paulus int w_size; 66 1.1 paulus int unit; 67 1.1 paulus int hdrlen; 68 1.1 paulus int mru; 69 1.1 paulus int debug; 70 1.1 paulus z_stream strm; 71 1.1 paulus struct compstat stats; 72 1.1 paulus }; 73 1.1 paulus 74 1.1 paulus #define DEFLATE_OVHD 2 /* Deflate overhead/packet */ 75 1.1 paulus 76 1.13 thorpej static void *zalloc(void *, u_int items, u_int size); 77 1.13 thorpej static void zfree(void *, void *ptr); 78 1.13 thorpej static void *z_comp_alloc(u_char *options, int opt_len); 79 1.13 thorpej static void *z_decomp_alloc(u_char *options, int opt_len); 80 1.13 thorpej static void z_comp_free(void *state); 81 1.13 thorpej static void z_decomp_free(void *state); 82 1.13 thorpej static int z_comp_init(void *state, u_char *options, int opt_len, 83 1.13 thorpej int unit, int hdrlen, int debug); 84 1.13 thorpej static int z_decomp_init(void *state, u_char *options, int opt_len, 85 1.13 thorpej int unit, int hdrlen, int mru, int debug); 86 1.13 thorpej static int z_compress(void *state, struct mbuf **mret, 87 1.13 thorpej struct mbuf *mp, int slen, int maxolen); 88 1.13 thorpej static void z_incomp(void *state, struct mbuf *dmsg); 89 1.13 thorpej static int z_decompress(void *state, struct mbuf *cmp, 90 1.13 thorpej struct mbuf **dmpp); 91 1.13 thorpej static void z_comp_reset(void *state); 92 1.13 thorpej static void z_decomp_reset(void *state); 93 1.13 thorpej static void z_comp_stats(void *state, struct compstat *stats); 94 1.1 paulus 95 1.1 paulus /* 96 1.1 paulus * Procedures exported to if_ppp.c. 97 1.1 paulus */ 98 1.19 cube static struct compressor ppp_deflate[2] = { { 99 1.18 cube .compress_proto = CI_DEFLATE, 100 1.18 cube .comp_alloc = z_comp_alloc, 101 1.18 cube .comp_free = z_comp_free, 102 1.18 cube .comp_init = z_comp_init, 103 1.18 cube .comp_reset = z_comp_reset, 104 1.18 cube .compress = z_compress, 105 1.18 cube .comp_stat = z_comp_stats, 106 1.18 cube .decomp_alloc = z_decomp_alloc, 107 1.18 cube .decomp_free = z_decomp_free, 108 1.18 cube .decomp_init = z_decomp_init, 109 1.18 cube .decomp_reset = z_decomp_reset, 110 1.18 cube .decompress = z_decompress, 111 1.18 cube .incomp = z_incomp, 112 1.18 cube .decomp_stat = z_comp_stats, 113 1.19 cube }, 114 1.19 cube { 115 1.18 cube .compress_proto = CI_DEFLATE_DRAFT, 116 1.18 cube .comp_alloc = z_comp_alloc, 117 1.18 cube .comp_free = z_comp_free, 118 1.18 cube .comp_init = z_comp_init, 119 1.18 cube .comp_reset = z_comp_reset, 120 1.18 cube .compress = z_compress, 121 1.18 cube .comp_stat = z_comp_stats, 122 1.18 cube .decomp_alloc = z_decomp_alloc, 123 1.18 cube .decomp_free = z_decomp_free, 124 1.18 cube .decomp_init = z_decomp_init, 125 1.18 cube .decomp_reset = z_decomp_reset, 126 1.18 cube .decompress = z_decompress, 127 1.18 cube .incomp = z_incomp, 128 1.18 cube .decomp_stat = z_comp_stats, 129 1.19 cube } }; 130 1.1 paulus /* 131 1.1 paulus * Space allocation and freeing routines for use by zlib routines. 132 1.1 paulus */ 133 1.1 paulus void * 134 1.15 christos zalloc(void *notused, u_int items, u_int size) 135 1.1 paulus { 136 1.1 paulus void *ptr; 137 1.1 paulus 138 1.7 thorpej ptr = malloc(items * size, M_DEVBUF, M_NOWAIT); 139 1.1 paulus return ptr; 140 1.1 paulus } 141 1.1 paulus 142 1.1 paulus void 143 1.15 christos zfree(void *notused, void *ptr) 144 1.1 paulus { 145 1.7 thorpej free(ptr, M_DEVBUF); 146 1.1 paulus } 147 1.1 paulus 148 1.1 paulus /* 149 1.1 paulus * Allocate space for a compressor. 150 1.1 paulus */ 151 1.1 paulus static void * 152 1.13 thorpej z_comp_alloc(u_char *options, int opt_len) 153 1.1 paulus { 154 1.1 paulus struct deflate_state *state; 155 1.1 paulus int w_size; 156 1.1 paulus 157 1.6 christos if (opt_len != CILEN_DEFLATE 158 1.6 christos || (options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT) 159 1.1 paulus || options[1] != CILEN_DEFLATE 160 1.1 paulus || DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL 161 1.1 paulus || options[3] != DEFLATE_CHK_SEQUENCE) 162 1.1 paulus return NULL; 163 1.1 paulus w_size = DEFLATE_SIZE(options[2]); 164 1.1 paulus if (w_size < DEFLATE_MIN_SIZE || w_size > DEFLATE_MAX_SIZE) 165 1.1 paulus return NULL; 166 1.1 paulus 167 1.20 cegger state = malloc(sizeof(struct deflate_state), M_DEVBUF, M_NOWAIT); 168 1.1 paulus if (state == NULL) 169 1.1 paulus return NULL; 170 1.1 paulus 171 1.1 paulus state->strm.next_in = NULL; 172 1.1 paulus state->strm.zalloc = zalloc; 173 1.1 paulus state->strm.zfree = zfree; 174 1.1 paulus if (deflateInit2(&state->strm, Z_DEFAULT_COMPRESSION, DEFLATE_METHOD_VAL, 175 1.6 christos -w_size, 8, Z_DEFAULT_STRATEGY) != Z_OK) { 176 1.20 cegger free(state, M_DEVBUF); 177 1.1 paulus return NULL; 178 1.1 paulus } 179 1.1 paulus 180 1.1 paulus state->w_size = w_size; 181 1.8 thorpej memset(&state->stats, 0, sizeof(state->stats)); 182 1.1 paulus return (void *) state; 183 1.1 paulus } 184 1.1 paulus 185 1.1 paulus static void 186 1.13 thorpej z_comp_free(void *arg) 187 1.1 paulus { 188 1.1 paulus struct deflate_state *state = (struct deflate_state *) arg; 189 1.1 paulus 190 1.1 paulus deflateEnd(&state->strm); 191 1.20 cegger free(state, M_DEVBUF); 192 1.1 paulus } 193 1.1 paulus 194 1.1 paulus static int 195 1.13 thorpej z_comp_init(void *arg, u_char *options, int opt_len, int unit, int hdrlen, 196 1.13 thorpej int debug) 197 1.1 paulus { 198 1.1 paulus struct deflate_state *state = (struct deflate_state *) arg; 199 1.1 paulus 200 1.6 christos if (opt_len < CILEN_DEFLATE 201 1.6 christos || (options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT) 202 1.1 paulus || options[1] != CILEN_DEFLATE 203 1.1 paulus || DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL 204 1.1 paulus || DEFLATE_SIZE(options[2]) != state->w_size 205 1.1 paulus || options[3] != DEFLATE_CHK_SEQUENCE) 206 1.1 paulus return 0; 207 1.1 paulus 208 1.1 paulus state->seqno = 0; 209 1.1 paulus state->unit = unit; 210 1.1 paulus state->hdrlen = hdrlen; 211 1.1 paulus state->debug = debug; 212 1.1 paulus 213 1.1 paulus deflateReset(&state->strm); 214 1.1 paulus 215 1.1 paulus return 1; 216 1.1 paulus } 217 1.1 paulus 218 1.1 paulus static void 219 1.13 thorpej z_comp_reset(void *arg) 220 1.1 paulus { 221 1.1 paulus struct deflate_state *state = (struct deflate_state *) arg; 222 1.1 paulus 223 1.1 paulus state->seqno = 0; 224 1.1 paulus deflateReset(&state->strm); 225 1.1 paulus } 226 1.1 paulus 227 1.1 paulus int 228 1.13 thorpej z_compress(void *arg, 229 1.13 thorpej struct mbuf **mret /* compressed packet (out) */, 230 1.13 thorpej struct mbuf *mp /* uncompressed packet (in) */, 231 1.13 thorpej int orig_len, int maxolen) 232 1.1 paulus { 233 1.1 paulus struct deflate_state *state = (struct deflate_state *) arg; 234 1.1 paulus u_char *rptr, *wptr; 235 1.1 paulus int proto, olen, wspace, r, flush; 236 1.1 paulus struct mbuf *m; 237 1.1 paulus 238 1.1 paulus /* 239 1.1 paulus * Check that the protocol is in the range we handle. 240 1.1 paulus */ 241 1.1 paulus rptr = mtod(mp, u_char *); 242 1.1 paulus proto = PPP_PROTOCOL(rptr); 243 1.1 paulus if (proto > 0x3fff || proto == 0xfd || proto == 0xfb) { 244 1.1 paulus *mret = NULL; 245 1.1 paulus return orig_len; 246 1.1 paulus } 247 1.1 paulus 248 1.1 paulus /* Allocate one mbuf initially. */ 249 1.1 paulus if (maxolen > orig_len) 250 1.1 paulus maxolen = orig_len; 251 1.1 paulus MGET(m, M_DONTWAIT, MT_DATA); 252 1.1 paulus *mret = m; 253 1.1 paulus if (m != NULL) { 254 1.1 paulus m->m_len = 0; 255 1.1 paulus if (maxolen + state->hdrlen > MLEN) 256 1.1 paulus MCLGET(m, M_DONTWAIT); 257 1.1 paulus wspace = M_TRAILINGSPACE(m); 258 1.1 paulus if (state->hdrlen + PPP_HDRLEN + 2 < wspace) { 259 1.1 paulus m->m_data += state->hdrlen; 260 1.1 paulus wspace -= state->hdrlen; 261 1.1 paulus } 262 1.1 paulus wptr = mtod(m, u_char *); 263 1.1 paulus 264 1.1 paulus /* 265 1.1 paulus * Copy over the PPP header and store the 2-byte sequence number. 266 1.1 paulus */ 267 1.1 paulus wptr[0] = PPP_ADDRESS(rptr); 268 1.1 paulus wptr[1] = PPP_CONTROL(rptr); 269 1.1 paulus wptr[2] = PPP_COMP >> 8; 270 1.1 paulus wptr[3] = PPP_COMP; 271 1.1 paulus wptr += PPP_HDRLEN; 272 1.1 paulus wptr[0] = state->seqno >> 8; 273 1.1 paulus wptr[1] = state->seqno; 274 1.1 paulus wptr += 2; 275 1.1 paulus state->strm.next_out = wptr; 276 1.1 paulus state->strm.avail_out = wspace - (PPP_HDRLEN + 2); 277 1.1 paulus } else { 278 1.1 paulus state->strm.next_out = NULL; 279 1.1 paulus state->strm.avail_out = 1000000; 280 1.1 paulus wptr = NULL; 281 1.1 paulus wspace = 0; 282 1.1 paulus } 283 1.1 paulus ++state->seqno; 284 1.1 paulus 285 1.1 paulus rptr += (proto > 0xff)? 2: 3; /* skip 1st proto byte if 0 */ 286 1.1 paulus state->strm.next_in = rptr; 287 1.1 paulus state->strm.avail_in = mtod(mp, u_char *) + mp->m_len - rptr; 288 1.1 paulus mp = mp->m_next; 289 1.1 paulus flush = (mp == NULL)? Z_PACKET_FLUSH: Z_NO_FLUSH; 290 1.1 paulus olen = 0; 291 1.1 paulus for (;;) { 292 1.1 paulus r = deflate(&state->strm, flush); 293 1.1 paulus if (r != Z_OK) { 294 1.3 christos printf("z_compress: deflate returned %d (%s)\n", 295 1.4 christos r, (state->strm.msg? state->strm.msg: "")); 296 1.1 paulus break; 297 1.1 paulus } 298 1.1 paulus if (flush != Z_NO_FLUSH && state->strm.avail_out != 0) 299 1.1 paulus break; /* all done */ 300 1.1 paulus if (state->strm.avail_in == 0 && mp != NULL) { 301 1.1 paulus state->strm.next_in = mtod(mp, u_char *); 302 1.1 paulus state->strm.avail_in = mp->m_len; 303 1.1 paulus mp = mp->m_next; 304 1.1 paulus if (mp == NULL) 305 1.1 paulus flush = Z_PACKET_FLUSH; 306 1.1 paulus } 307 1.1 paulus if (state->strm.avail_out == 0) { 308 1.1 paulus if (m != NULL) { 309 1.1 paulus m->m_len = wspace; 310 1.1 paulus olen += wspace; 311 1.1 paulus MGET(m->m_next, M_DONTWAIT, MT_DATA); 312 1.1 paulus m = m->m_next; 313 1.1 paulus if (m != NULL) { 314 1.1 paulus m->m_len = 0; 315 1.1 paulus if (maxolen - olen > MLEN) 316 1.1 paulus MCLGET(m, M_DONTWAIT); 317 1.1 paulus state->strm.next_out = mtod(m, u_char *); 318 1.1 paulus state->strm.avail_out = wspace = M_TRAILINGSPACE(m); 319 1.1 paulus } 320 1.1 paulus } 321 1.1 paulus if (m == NULL) { 322 1.1 paulus state->strm.next_out = NULL; 323 1.1 paulus state->strm.avail_out = 1000000; 324 1.1 paulus } 325 1.1 paulus } 326 1.1 paulus } 327 1.1 paulus if (m != NULL) 328 1.1 paulus olen += (m->m_len = wspace - state->strm.avail_out); 329 1.1 paulus 330 1.1 paulus /* 331 1.1 paulus * See if we managed to reduce the size of the packet. 332 1.1 paulus */ 333 1.6 christos if (m != NULL && olen < orig_len) { 334 1.1 paulus state->stats.comp_bytes += olen; 335 1.1 paulus state->stats.comp_packets++; 336 1.1 paulus } else { 337 1.24 rin m_freem(*mret); 338 1.24 rin *mret = NULL; 339 1.1 paulus state->stats.inc_bytes += orig_len; 340 1.1 paulus state->stats.inc_packets++; 341 1.1 paulus olen = orig_len; 342 1.1 paulus } 343 1.1 paulus state->stats.unc_bytes += orig_len; 344 1.1 paulus state->stats.unc_packets++; 345 1.1 paulus 346 1.1 paulus return olen; 347 1.1 paulus } 348 1.1 paulus 349 1.1 paulus static void 350 1.13 thorpej z_comp_stats(void *arg, struct compstat *stats) 351 1.1 paulus { 352 1.1 paulus struct deflate_state *state = (struct deflate_state *) arg; 353 1.1 paulus u_int out; 354 1.1 paulus 355 1.1 paulus *stats = state->stats; 356 1.1 paulus stats->ratio = stats->unc_bytes; 357 1.1 paulus out = stats->comp_bytes + stats->inc_bytes; 358 1.1 paulus if (stats->ratio <= 0x7ffffff) 359 1.1 paulus stats->ratio <<= 8; 360 1.1 paulus else 361 1.1 paulus out >>= 8; 362 1.1 paulus if (out != 0) 363 1.1 paulus stats->ratio /= out; 364 1.1 paulus } 365 1.1 paulus 366 1.1 paulus /* 367 1.1 paulus * Allocate space for a decompressor. 368 1.1 paulus */ 369 1.1 paulus static void * 370 1.13 thorpej z_decomp_alloc(u_char *options, int opt_len) 371 1.1 paulus { 372 1.1 paulus struct deflate_state *state; 373 1.1 paulus int w_size; 374 1.1 paulus 375 1.6 christos if (opt_len != CILEN_DEFLATE 376 1.6 christos || (options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT) 377 1.1 paulus || options[1] != CILEN_DEFLATE 378 1.1 paulus || DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL 379 1.1 paulus || options[3] != DEFLATE_CHK_SEQUENCE) 380 1.1 paulus return NULL; 381 1.1 paulus w_size = DEFLATE_SIZE(options[2]); 382 1.1 paulus if (w_size < DEFLATE_MIN_SIZE || w_size > DEFLATE_MAX_SIZE) 383 1.1 paulus return NULL; 384 1.1 paulus 385 1.20 cegger state = malloc(sizeof(struct deflate_state), M_DEVBUF, M_NOWAIT); 386 1.1 paulus if (state == NULL) 387 1.1 paulus return NULL; 388 1.1 paulus 389 1.1 paulus state->strm.next_out = NULL; 390 1.1 paulus state->strm.zalloc = zalloc; 391 1.1 paulus state->strm.zfree = zfree; 392 1.1 paulus if (inflateInit2(&state->strm, -w_size) != Z_OK) { 393 1.20 cegger free(state, M_DEVBUF); 394 1.1 paulus return NULL; 395 1.1 paulus } 396 1.1 paulus 397 1.1 paulus state->w_size = w_size; 398 1.8 thorpej memset(&state->stats, 0, sizeof(state->stats)); 399 1.1 paulus return (void *) state; 400 1.1 paulus } 401 1.1 paulus 402 1.1 paulus static void 403 1.13 thorpej z_decomp_free(void *arg) 404 1.1 paulus { 405 1.1 paulus struct deflate_state *state = (struct deflate_state *) arg; 406 1.1 paulus 407 1.1 paulus inflateEnd(&state->strm); 408 1.20 cegger free(state, M_DEVBUF); 409 1.1 paulus } 410 1.1 paulus 411 1.1 paulus static int 412 1.13 thorpej z_decomp_init(void *arg, u_char *options, int opt_len, int unit, int hdrlen, 413 1.13 thorpej int mru, int debug) 414 1.1 paulus { 415 1.1 paulus struct deflate_state *state = (struct deflate_state *) arg; 416 1.1 paulus 417 1.6 christos if (opt_len < CILEN_DEFLATE 418 1.6 christos || (options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT) 419 1.1 paulus || options[1] != CILEN_DEFLATE 420 1.1 paulus || DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL 421 1.1 paulus || DEFLATE_SIZE(options[2]) != state->w_size 422 1.1 paulus || options[3] != DEFLATE_CHK_SEQUENCE) 423 1.1 paulus return 0; 424 1.1 paulus 425 1.1 paulus state->seqno = 0; 426 1.1 paulus state->unit = unit; 427 1.1 paulus state->hdrlen = hdrlen; 428 1.1 paulus state->debug = debug; 429 1.1 paulus state->mru = mru; 430 1.1 paulus 431 1.1 paulus inflateReset(&state->strm); 432 1.1 paulus 433 1.1 paulus return 1; 434 1.1 paulus } 435 1.1 paulus 436 1.1 paulus static void 437 1.13 thorpej z_decomp_reset(void *arg) 438 1.1 paulus { 439 1.1 paulus struct deflate_state *state = (struct deflate_state *) arg; 440 1.1 paulus 441 1.1 paulus state->seqno = 0; 442 1.1 paulus inflateReset(&state->strm); 443 1.1 paulus } 444 1.1 paulus 445 1.1 paulus /* 446 1.1 paulus * Decompress a Deflate-compressed packet. 447 1.1 paulus * 448 1.1 paulus * Because of patent problems, we return DECOMP_ERROR for errors 449 1.1 paulus * found by inspecting the input data and for system problems, but 450 1.1 paulus * DECOMP_FATALERROR for any errors which could possibly be said to 451 1.1 paulus * be being detected "after" decompression. For DECOMP_ERROR, 452 1.1 paulus * we can issue a CCP reset-request; for DECOMP_FATALERROR, we may be 453 1.1 paulus * infringing a patent of Motorola's if we do, so we take CCP down 454 1.1 paulus * instead. 455 1.1 paulus * 456 1.1 paulus * Given that the frame has the correct sequence number and a good FCS, 457 1.1 paulus * errors such as invalid codes in the input most likely indicate a 458 1.1 paulus * bug, so we return DECOMP_FATALERROR for them in order to turn off 459 1.1 paulus * compression, even though they are detected by inspecting the input. 460 1.1 paulus */ 461 1.1 paulus int 462 1.13 thorpej z_decompress(void *arg, struct mbuf *mi, struct mbuf **mop) 463 1.1 paulus { 464 1.1 paulus struct deflate_state *state = (struct deflate_state *) arg; 465 1.1 paulus struct mbuf *mo, *mo_head; 466 1.1 paulus u_char *rptr, *wptr; 467 1.1 paulus int rlen, olen, ospace; 468 1.1 paulus int seq, i, flush, r, decode_proto; 469 1.1 paulus u_char hdr[PPP_HDRLEN + DEFLATE_OVHD]; 470 1.1 paulus 471 1.1 paulus *mop = NULL; 472 1.1 paulus rptr = mtod(mi, u_char *); 473 1.1 paulus rlen = mi->m_len; 474 1.1 paulus for (i = 0; i < PPP_HDRLEN + DEFLATE_OVHD; ++i) { 475 1.1 paulus while (rlen <= 0) { 476 1.1 paulus mi = mi->m_next; 477 1.1 paulus if (mi == NULL) 478 1.1 paulus return DECOMP_ERROR; 479 1.1 paulus rptr = mtod(mi, u_char *); 480 1.1 paulus rlen = mi->m_len; 481 1.1 paulus } 482 1.1 paulus hdr[i] = *rptr++; 483 1.1 paulus --rlen; 484 1.1 paulus } 485 1.1 paulus 486 1.1 paulus /* Check the sequence number. */ 487 1.1 paulus seq = (hdr[PPP_HDRLEN] << 8) + hdr[PPP_HDRLEN+1]; 488 1.1 paulus if (seq != state->seqno) { 489 1.1 paulus if (state->debug) 490 1.3 christos printf("z_decompress%d: bad seq # %d, expected %d\n", 491 1.4 christos state->unit, seq, state->seqno); 492 1.1 paulus return DECOMP_ERROR; 493 1.1 paulus } 494 1.1 paulus ++state->seqno; 495 1.1 paulus 496 1.1 paulus /* Allocate an output mbuf. */ 497 1.1 paulus MGETHDR(mo, M_DONTWAIT, MT_DATA); 498 1.1 paulus if (mo == NULL) 499 1.1 paulus return DECOMP_ERROR; 500 1.1 paulus mo_head = mo; 501 1.1 paulus mo->m_len = 0; 502 1.1 paulus mo->m_next = NULL; 503 1.1 paulus MCLGET(mo, M_DONTWAIT); 504 1.1 paulus ospace = M_TRAILINGSPACE(mo); 505 1.1 paulus if (state->hdrlen + PPP_HDRLEN < ospace) { 506 1.1 paulus mo->m_data += state->hdrlen; 507 1.1 paulus ospace -= state->hdrlen; 508 1.1 paulus } 509 1.1 paulus 510 1.1 paulus /* 511 1.1 paulus * Fill in the first part of the PPP header. The protocol field 512 1.1 paulus * comes from the decompressed data. 513 1.1 paulus */ 514 1.1 paulus wptr = mtod(mo, u_char *); 515 1.1 paulus wptr[0] = PPP_ADDRESS(hdr); 516 1.1 paulus wptr[1] = PPP_CONTROL(hdr); 517 1.1 paulus wptr[2] = 0; 518 1.1 paulus 519 1.1 paulus /* 520 1.1 paulus * Set up to call inflate. We set avail_out to 1 initially so we can 521 1.1 paulus * look at the first byte of the output and decide whether we have 522 1.1 paulus * a 1-byte or 2-byte protocol field. 523 1.1 paulus */ 524 1.1 paulus state->strm.next_in = rptr; 525 1.1 paulus state->strm.avail_in = rlen; 526 1.1 paulus mi = mi->m_next; 527 1.1 paulus flush = (mi == NULL)? Z_PACKET_FLUSH: Z_NO_FLUSH; 528 1.1 paulus rlen += PPP_HDRLEN + DEFLATE_OVHD; 529 1.1 paulus state->strm.next_out = wptr + 3; 530 1.1 paulus state->strm.avail_out = 1; 531 1.1 paulus decode_proto = 1; 532 1.11 fvdl olen = 0; 533 1.1 paulus 534 1.1 paulus /* 535 1.1 paulus * Call inflate, supplying more input or output as needed. 536 1.1 paulus */ 537 1.1 paulus for (;;) { 538 1.1 paulus r = inflate(&state->strm, flush); 539 1.1 paulus if (r != Z_OK) { 540 1.4 christos #if !DEFLATE_DEBUG 541 1.1 paulus if (state->debug) 542 1.4 christos #endif 543 1.3 christos printf("z_decompress%d: inflate returned %d (%s)\n", 544 1.4 christos state->unit, r, (state->strm.msg? state->strm.msg: "")); 545 1.1 paulus m_freem(mo_head); 546 1.1 paulus return DECOMP_FATALERROR; 547 1.1 paulus } 548 1.1 paulus if (flush != Z_NO_FLUSH && state->strm.avail_out != 0) 549 1.1 paulus break; /* all done */ 550 1.1 paulus if (state->strm.avail_in == 0 && mi != NULL) { 551 1.1 paulus state->strm.next_in = mtod(mi, u_char *); 552 1.1 paulus state->strm.avail_in = mi->m_len; 553 1.1 paulus rlen += mi->m_len; 554 1.1 paulus mi = mi->m_next; 555 1.1 paulus if (mi == NULL) 556 1.1 paulus flush = Z_PACKET_FLUSH; 557 1.1 paulus } 558 1.1 paulus if (state->strm.avail_out == 0) { 559 1.1 paulus if (decode_proto) { 560 1.1 paulus state->strm.avail_out = ospace - PPP_HDRLEN; 561 1.1 paulus if ((wptr[3] & 1) == 0) { 562 1.1 paulus /* 2-byte protocol field */ 563 1.1 paulus wptr[2] = wptr[3]; 564 1.1 paulus --state->strm.next_out; 565 1.1 paulus ++state->strm.avail_out; 566 1.1 paulus --olen; 567 1.1 paulus } 568 1.1 paulus decode_proto = 0; 569 1.1 paulus } else { 570 1.1 paulus mo->m_len = ospace; 571 1.1 paulus olen += ospace; 572 1.1 paulus MGET(mo->m_next, M_DONTWAIT, MT_DATA); 573 1.1 paulus mo = mo->m_next; 574 1.1 paulus if (mo == NULL) { 575 1.1 paulus m_freem(mo_head); 576 1.1 paulus return DECOMP_ERROR; 577 1.1 paulus } 578 1.1 paulus MCLGET(mo, M_DONTWAIT); 579 1.1 paulus state->strm.next_out = mtod(mo, u_char *); 580 1.1 paulus state->strm.avail_out = ospace = M_TRAILINGSPACE(mo); 581 1.1 paulus } 582 1.1 paulus } 583 1.1 paulus } 584 1.1 paulus if (decode_proto) { 585 1.1 paulus m_freem(mo_head); 586 1.1 paulus return DECOMP_ERROR; 587 1.1 paulus } 588 1.1 paulus olen += (mo->m_len = ospace - state->strm.avail_out); 589 1.4 christos #if DEFLATE_DEBUG 590 1.4 christos if (olen > state->mru + PPP_HDRLEN) 591 1.4 christos printf("ppp_deflate%d: exceeded mru (%d > %d)\n", 592 1.4 christos state->unit, olen, state->mru + PPP_HDRLEN); 593 1.4 christos #endif 594 1.1 paulus 595 1.1 paulus state->stats.unc_bytes += olen; 596 1.1 paulus state->stats.unc_packets++; 597 1.1 paulus state->stats.comp_bytes += rlen; 598 1.1 paulus state->stats.comp_packets++; 599 1.1 paulus 600 1.1 paulus *mop = mo_head; 601 1.1 paulus return DECOMP_OK; 602 1.1 paulus } 603 1.1 paulus 604 1.1 paulus /* 605 1.1 paulus * Incompressible data has arrived - add it to the history. 606 1.1 paulus */ 607 1.1 paulus static void 608 1.13 thorpej z_incomp(void *arg, struct mbuf *mi) 609 1.1 paulus { 610 1.1 paulus struct deflate_state *state = (struct deflate_state *) arg; 611 1.1 paulus u_char *rptr; 612 1.1 paulus int rlen, proto, r; 613 1.1 paulus 614 1.1 paulus /* 615 1.1 paulus * Check that the protocol is one we handle. 616 1.1 paulus */ 617 1.1 paulus rptr = mtod(mi, u_char *); 618 1.1 paulus proto = PPP_PROTOCOL(rptr); 619 1.1 paulus if (proto > 0x3fff || proto == 0xfd || proto == 0xfb) 620 1.1 paulus return; 621 1.1 paulus 622 1.1 paulus ++state->seqno; 623 1.1 paulus 624 1.1 paulus /* 625 1.1 paulus * Iterate through the mbufs, adding the characters in them 626 1.1 paulus * to the decompressor's history. For the first mbuf, we start 627 1.1 paulus * at the either the 1st or 2nd byte of the protocol field, 628 1.1 paulus * depending on whether the protocol value is compressible. 629 1.1 paulus */ 630 1.1 paulus rlen = mi->m_len; 631 1.1 paulus state->strm.next_in = rptr + 3; 632 1.1 paulus state->strm.avail_in = rlen - 3; 633 1.1 paulus if (proto > 0xff) { 634 1.1 paulus --state->strm.next_in; 635 1.1 paulus ++state->strm.avail_in; 636 1.1 paulus } 637 1.1 paulus for (;;) { 638 1.1 paulus r = inflateIncomp(&state->strm); 639 1.1 paulus if (r != Z_OK) { 640 1.1 paulus /* gak! */ 641 1.4 christos #if !DEFLATE_DEBUG 642 1.4 christos if (state->debug) 643 1.4 christos #endif 644 1.3 christos printf("z_incomp%d: inflateIncomp returned %d (%s)\n", 645 1.4 christos state->unit, r, (state->strm.msg? state->strm.msg: "")); 646 1.1 paulus return; 647 1.1 paulus } 648 1.1 paulus mi = mi->m_next; 649 1.1 paulus if (mi == NULL) 650 1.1 paulus break; 651 1.1 paulus state->strm.next_in = mtod(mi, u_char *); 652 1.1 paulus state->strm.avail_in = mi->m_len; 653 1.1 paulus rlen += mi->m_len; 654 1.1 paulus } 655 1.1 paulus 656 1.1 paulus /* 657 1.1 paulus * Update stats. 658 1.1 paulus */ 659 1.1 paulus state->stats.inc_bytes += rlen; 660 1.1 paulus state->stats.inc_packets++; 661 1.1 paulus state->stats.unc_bytes += rlen; 662 1.1 paulus state->stats.unc_packets++; 663 1.1 paulus } 664 1.1 paulus 665 1.23 pgoyette MODULE(MODULE_CLASS_MISC, ppp_deflate, "zlib,if_ppp"); 666 1.18 cube 667 1.18 cube static int 668 1.18 cube ppp_deflate_modcmd(modcmd_t cmd, void *arg) 669 1.18 cube { 670 1.18 cube 671 1.18 cube switch (cmd) { 672 1.18 cube case MODULE_CMD_INIT: 673 1.19 cube return ppp_register_compressor(ppp_deflate, 2); 674 1.18 cube case MODULE_CMD_FINI: 675 1.19 cube return ppp_unregister_compressor(ppp_deflate, 2); 676 1.18 cube case MODULE_CMD_STAT: 677 1.18 cube return 0; 678 1.18 cube default: 679 1.18 cube return ENOTTY; 680 1.18 cube } 681 1.18 cube 682 1.18 cube return ENOTTY; 683 1.18 cube } 684 1.1 paulus #endif /* DO_DEFLATE */ 685