// SPDX-License-Identifier: GPL-2.0-only /* * ppp_deflate.c - interface the zlib procedures for Deflate compression * and decompression (as used by gzip) to the PPP code. * * Copyright 1994-1998 Paul Mackerras.
*/
/* * State for a Deflate (de)compressor.
*/ struct ppp_deflate_state { int seqno; int w_size; int unit; int mru; int debug;
z_stream strm; struct compstat stats;
};
staticvoid *z_comp_alloc(unsignedchar *options, int opt_len); staticvoid *z_decomp_alloc(unsignedchar *options, int opt_len); staticvoid z_comp_free(void *state); staticvoid z_decomp_free(void *state); staticint z_comp_init(void *state, unsignedchar *options, int opt_len, int unit, int hdrlen, int debug); staticint z_decomp_init(void *state, unsignedchar *options, int opt_len, int unit, int hdrlen, int mru, int debug); staticint z_compress(void *state, unsignedchar *rptr, unsignedchar *obuf, int isize, int osize); staticvoid z_incomp(void *state, unsignedchar *ibuf, int icnt); staticint z_decompress(void *state, unsignedchar *ibuf, int isize, unsignedchar *obuf, int osize); staticvoid z_comp_reset(void *state); staticvoid z_decomp_reset(void *state); staticvoid z_comp_stats(void *state, struct compstat *stats);
/** * z_comp_free - free the memory used by a compressor * @arg: pointer to the private state for the compressor.
*/ staticvoid z_comp_free(void *arg)
{ struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg;
if (state) {
zlib_deflateEnd(&state->strm);
vfree(state->strm.workspace);
kfree(state);
}
}
/**
* z_comp_alloc - allocate space for a compressor.
* @options: pointer to CCP option data
* @opt_len: length of the CCP option at @options.
*
* The @options pointer points to the a buffer containing the
* CCP option data for the compression being negotiated. It is
* formatted according to RFC1979, and describes the window
* size that the peer is requesting that we use in compressing
* data to be sent to it.
*
* Returns the pointer to the private state for the compressor,
* or NULL if we could not allocate enough memory.
*/ staticvoid *z_comp_alloc(unsignedchar *options, int opt_len)
{ struct ppp_deflate_state *state; int w_size;
/** * z_comp_init - initialize a previously-allocated compressor. * @arg: pointer to the private state for the compressor * @options: pointer to the CCP option data describing the * compression that was negotiated with the peer * @opt_len: length of the CCP option data at @options * @unit: PPP unit number for diagnostic messages * @hdrlen: ignored (present for backwards compatibility) * @debug: debug flag; if non-zero, debug messages are printed. * * The CCP options described by @options must match the options * specified when the compressor was allocated. The compressor * history is reset. Returns 0 for failure (CCP options don't * match) or 1 for success.
*/ staticint z_comp_init(void *arg, unsignedchar *options, int opt_len, int unit, int hdrlen, int debug)
{ struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg;
/** * z_comp_reset - reset a previously-allocated compressor. * @arg: pointer to private state for the compressor. * * This clears the history for the compressor and makes it * ready to start emitting a new compressed stream.
*/ staticvoid z_comp_reset(void *arg)
{ struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg;
/** * z_compress - compress a PPP packet with Deflate compression. * @arg: pointer to private state for the compressor * @rptr: uncompressed packet (input) * @obuf: compressed packet (output) * @isize: size of uncompressed packet * @osize: space available at @obuf * * Returns the length of the compressed packet, or 0 if the * packet is incompressible.
*/ staticint z_compress(void *arg, unsignedchar *rptr, unsignedchar *obuf, int isize, int osize)
{ struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg; int r, proto, off, olen, oavail; unsignedchar *wptr;
/* * Check that the protocol is in the range we handle.
*/
proto = PPP_PROTOCOL(rptr); if (proto > 0x3fff || proto == 0xfd || proto == 0xfb) return 0;
/* Don't generate compressed packets which are larger than
the uncompressed packet. */ if (osize > isize)
osize = isize;
wptr = obuf;
/* * Copy over the PPP header and store the 2-byte sequence number.
*/
wptr[0] = PPP_ADDRESS(rptr);
wptr[1] = PPP_CONTROL(rptr);
put_unaligned_be16(PPP_COMP, wptr + 2);
wptr += PPP_HDRLEN;
put_unaligned_be16(state->seqno, wptr);
wptr += DEFLATE_OVHD;
olen = PPP_HDRLEN + DEFLATE_OVHD;
state->strm.next_out = wptr;
state->strm.avail_out = oavail = osize - olen;
++state->seqno;
off = (proto > 0xff) ? 2 : 3; /* skip 1st proto byte if 0 */
rptr += off;
state->strm.next_in = rptr;
state->strm.avail_in = (isize - off);
for (;;) {
r = zlib_deflate(&state->strm, Z_PACKET_FLUSH); if (r != Z_OK) { if (state->debug)
printk(KERN_ERR "z_compress: deflate returned %d\n", r); break;
} if (state->strm.avail_out == 0) {
olen += oavail;
state->strm.next_out = NULL;
state->strm.avail_out = oavail = 1000000;
} else { break; /* all done */
}
}
olen += oavail - state->strm.avail_out;
/* * See if we managed to reduce the size of the packet.
*/ if (olen < isize && olen <= osize) {
state->stats.comp_bytes += olen;
state->stats.comp_packets++;
} else {
state->stats.inc_bytes += isize;
state->stats.inc_packets++;
olen = 0;
}
state->stats.unc_bytes += isize;
state->stats.unc_packets++;
return olen;
}
/** * z_comp_stats - return compression statistics for a compressor * or decompressor. * @arg: pointer to private space for the (de)compressor * @stats: pointer to a struct compstat to receive the result.
*/ staticvoid z_comp_stats(void *arg, struct compstat *stats)
{ struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg;
*stats = state->stats;
}
/** * z_decomp_free - Free the memory used by a decompressor. * @arg: pointer to private space for the decompressor.
*/ staticvoid z_decomp_free(void *arg)
{ struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg;
if (state) {
vfree(state->strm.workspace);
kfree(state);
}
}
/** * z_decomp_alloc - allocate space for a decompressor. * @options: pointer to CCP option data * @opt_len: length of the CCP option at @options. * * The @options pointer points to the a buffer containing the * CCP option data for the compression being negotiated. It is * formatted according to RFC1979, and describes the window * size that we are requesting the peer to use in compressing * data to be sent to us. * * Returns the pointer to the private state for the decompressor, * or NULL if we could not allocate enough memory.
*/ staticvoid *z_decomp_alloc(unsignedchar *options, int opt_len)
{ struct ppp_deflate_state *state; int w_size;
/** * z_decomp_init - initialize a previously-allocated decompressor. * @arg: pointer to the private state for the decompressor * @options: pointer to the CCP option data describing the * compression that was negotiated with the peer * @opt_len: length of the CCP option data at @options * @unit: PPP unit number for diagnostic messages * @hdrlen: ignored (present for backwards compatibility) * @mru: maximum length of decompressed packets * @debug: debug flag; if non-zero, debug messages are printed. * * The CCP options described by @options must match the options * specified when the decompressor was allocated. The decompressor * history is reset. Returns 0 for failure (CCP options don't * match) or 1 for success.
*/ staticint z_decomp_init(void *arg, unsignedchar *options, int opt_len, int unit, int hdrlen, int mru, int debug)
{ struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg;
/** * z_decomp_reset - reset a previously-allocated decompressor. * @arg: pointer to private state for the decompressor. * * This clears the history for the decompressor and makes it * ready to receive a new compressed stream.
*/ staticvoid z_decomp_reset(void *arg)
{ struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg;
/** * z_decompress - decompress a Deflate-compressed packet. * @arg: pointer to private state for the decompressor * @ibuf: pointer to input (compressed) packet data * @isize: length of input packet * @obuf: pointer to space for output (decompressed) packet * @osize: amount of space available at @obuf * * Because of patent problems, we return DECOMP_ERROR for errors * found by inspecting the input data and for system problems, but * DECOMP_FATALERROR for any errors which could possibly be said to * be being detected "after" decompression. For DECOMP_ERROR, * we can issue a CCP reset-request; for DECOMP_FATALERROR, we may be * infringing a patent of Motorola's if we do, so we take CCP down * instead. * * Given that the frame has the correct sequence number and a good FCS, * errors such as invalid codes in the input most likely indicate a * bug, so we return DECOMP_FATALERROR for them in order to turn off * compression, even though they are detected by inspecting the input.
*/ staticint z_decompress(void *arg, unsignedchar *ibuf, int isize, unsignedchar *obuf, int osize)
{ struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg; int olen, seq, r; int decode_proto, overflow; unsignedchar overflow_buf[1];
if (isize <= PPP_HDRLEN + DEFLATE_OVHD) { if (state->debug)
printk(KERN_DEBUG "z_decompress%d: short pkt (%d)\n",
state->unit, isize); return DECOMP_ERROR;
}
/* Check the sequence number. */
seq = get_unaligned_be16(ibuf + PPP_HDRLEN); if (seq != (state->seqno & 0xffff)) { if (state->debug)
printk(KERN_DEBUG "z_decompress%d: bad seq # %d, expected %d\n",
state->unit, seq, state->seqno & 0xffff); return DECOMP_ERROR;
}
++state->seqno;
/* * Fill in the first part of the PPP header. The protocol field * comes from the decompressed data.
*/
obuf[0] = PPP_ADDRESS(ibuf);
obuf[1] = PPP_CONTROL(ibuf);
obuf[2] = 0;
/* * Set up to call inflate. We set avail_out to 1 initially so we can * look at the first byte of the output and decide whether we have * a 1-byte or 2-byte protocol field.
*/
state->strm.next_in = ibuf + PPP_HDRLEN + DEFLATE_OVHD;
state->strm.avail_in = isize - (PPP_HDRLEN + DEFLATE_OVHD);
state->strm.next_out = obuf + 3;
state->strm.avail_out = 1;
decode_proto = 1;
overflow = 0;
/* * Call inflate, supplying more input or output as needed.
*/ for (;;) {
r = zlib_inflate(&state->strm, Z_PACKET_FLUSH); if (r != Z_OK) { if (state->debug)
printk(KERN_DEBUG "z_decompress%d: inflate returned %d (%s)\n",
state->unit, r, (state->strm.msg? state->strm.msg: "")); return DECOMP_FATALERROR;
} if (state->strm.avail_out != 0) break; /* all done */ if (decode_proto) {
state->strm.avail_out = osize - PPP_HDRLEN; if ((obuf[3] & 1) == 0) { /* 2-byte protocol field */
obuf[2] = obuf[3];
--state->strm.next_out;
++state->strm.avail_out;
}
decode_proto = 0;
} elseif (!overflow) { /* * We've filled up the output buffer; the only way to * find out whether inflate has any more characters * left is to give it another byte of output space.
*/
state->strm.next_out = overflow_buf;
state->strm.avail_out = 1;
overflow = 1;
} else { if (state->debug)
printk(KERN_DEBUG "z_decompress%d: ran out of mru\n",
state->unit); return DECOMP_FATALERROR;
}
}
if (decode_proto) { if (state->debug)
printk(KERN_DEBUG "z_decompress%d: didn't get proto\n",
state->unit); return DECOMP_ERROR;
}
/** * z_incomp - add incompressible input data to the history. * @arg: pointer to private state for the decompressor * @ibuf: pointer to input packet data * @icnt: length of input data.
*/ staticvoid z_incomp(void *arg, unsignedchar *ibuf, int icnt)
{ struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg; int proto, r;
/* * Check that the protocol is one we handle.
*/
proto = PPP_PROTOCOL(ibuf); if (proto > 0x3fff || proto == 0xfd || proto == 0xfb) return;
++state->seqno;
/* * We start at the either the 1st or 2nd byte of the protocol field, * depending on whether the protocol value is compressible.
*/
state->strm.next_in = ibuf + 3;
state->strm.avail_in = icnt - 3; if (proto > 0xff) {
--state->strm.next_in;
++state->strm.avail_in;
}
r = zlib_inflateIncomp(&state->strm); if (r != Z_OK) { /* gak! */ if (state->debug) {
printk(KERN_DEBUG "z_incomp%d: inflateIncomp returned %d (%s)\n",
state->unit, r, (state->strm.msg? state->strm.msg: ""));
} return;
}
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.6Bemerkung:
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.