ppp_deflate.c

来自「linux 内核源代码」· C语言 代码 · 共 656 行 · 第 1/2 页

C
656
字号
/* *  ==FILEVERSION 980319== * * ppp_deflate.c - interface the zlib procedures for Deflate compression * and decompression (as used by gzip) to the PPP code. * This version is for use with Linux kernel 1.3.X. * * Copyright (c) 1994 The Australian National University. * All rights reserved. * * Permission to use, copy, modify, and distribute this software and its * documentation is hereby granted, provided that the above copyright * notice appears in all copies.  This software is provided without any * warranty, express or implied. The Australian National University * makes no representations about the suitability of this software for * any purpose. * * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF * THE AUSTRALIAN NATIONAL UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, * OR MODIFICATIONS. * * From: deflate.c,v 1.1 1996/01/18 03:17:48 paulus Exp */#include <linux/module.h>#include <linux/slab.h>#include <linux/vmalloc.h>#include <linux/init.h>#include <linux/string.h>#include <linux/ppp_defs.h>#include <linux/ppp-comp.h>#include <linux/zlib.h>/* * 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;};#define DEFLATE_OVHD	2		/* Deflate overhead/packet */static void	*z_comp_alloc(unsigned char *options, int opt_len);static void	*z_decomp_alloc(unsigned char *options, int opt_len);static void	z_comp_free(void *state);static void	z_decomp_free(void *state);static int	z_comp_init(void *state, unsigned char *options,				 int opt_len,				 int unit, int hdrlen, int debug);static int	z_decomp_init(void *state, unsigned char *options,				   int opt_len,				   int unit, int hdrlen, int mru, int debug);static int	z_compress(void *state, unsigned char *rptr,				unsigned char *obuf,				int isize, int osize);static void	z_incomp(void *state, unsigned char *ibuf, int icnt);static int	z_decompress(void *state, unsigned char *ibuf,				int isize, unsigned char *obuf, int osize);static void	z_comp_reset(void *state);static void	z_decomp_reset(void *state);static void	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. */static void 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. */static void *z_comp_alloc(unsigned char *options, int opt_len){	struct ppp_deflate_state *state;	int w_size;	if (opt_len != CILEN_DEFLATE	    || (options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT)	    || options[1] != CILEN_DEFLATE	    || DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL	    || options[3] != DEFLATE_CHK_SEQUENCE)		return NULL;	w_size = DEFLATE_SIZE(options[2]);	if (w_size < DEFLATE_MIN_SIZE || w_size > DEFLATE_MAX_SIZE)		return NULL;	state = kzalloc(sizeof(*state),						     GFP_KERNEL);	if (state == NULL)		return NULL;	state->strm.next_in   = NULL;	state->w_size         = w_size;	state->strm.workspace = vmalloc(zlib_deflate_workspacesize());	if (state->strm.workspace == NULL)		goto out_free;	if (zlib_deflateInit2(&state->strm, Z_DEFAULT_COMPRESSION,			 DEFLATE_METHOD_VAL, -w_size, 8, Z_DEFAULT_STRATEGY)	    != Z_OK)		goto out_free;	return (void *) state;out_free:	z_comp_free(state);	return NULL;}/** *	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. */static int z_comp_init(void *arg, unsigned char *options, int opt_len,		       int unit, int hdrlen, int debug){	struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg;	if (opt_len < CILEN_DEFLATE	    || (options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT)	    || options[1] != CILEN_DEFLATE	    || DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL	    || DEFLATE_SIZE(options[2]) != state->w_size	    || options[3] != DEFLATE_CHK_SEQUENCE)		return 0;	state->seqno = 0;	state->unit  = unit;	state->debug = debug;	zlib_deflateReset(&state->strm);	return 1;}/** *	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. */static void z_comp_reset(void *arg){	struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg;	state->seqno = 0;	zlib_deflateReset(&state->strm);}/** *	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. */int z_compress(void *arg, unsigned char *rptr, unsigned char *obuf,	       int isize, int osize){	struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg;	int r, proto, off, olen, oavail;	unsigned char *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);	wptr[2] = PPP_COMP >> 8;	wptr[3] = PPP_COMP;	wptr += PPP_HDRLEN;	wptr[0] = state->seqno >> 8;	wptr[1] = state->seqno;	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) {		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. */static void 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. */static void z_decomp_free(void *arg){	struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg;	if (state) {		zlib_inflateEnd(&state->strm);		kfree(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. */static void *z_decomp_alloc(unsigned char *options, int opt_len)

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?