/*
- * ==FILEVERSION 960302==
+ * ==FILEVERSION 970428==
*
* ppp_deflate.c - interface the zlib procedures for Deflate compression
* and decompression (as used by gzip) to the PPP code.
#include <linux/module.h>
-#include <endian.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/types.h>
#include <linux/ioport.h>
#include <linux/in.h>
#include <linux/malloc.h>
-#include <linux/tty.h>
+#include <linux/vmalloc.h>
#include <linux/errno.h>
#include <linux/sched.h> /* to get the struct task_struct */
#include <linux/string.h> /* used in new tty drivers */
#include <linux/signal.h> /* used in new tty drivers */
#include <asm/system.h>
-#include <asm/bitops.h>
-#include <asm/segment.h>
-#include <net/if.h>
-
-#include <linux/if_ether.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/inet.h>
#include <linux/ioctl.h>
#include <linux/ppp_defs.h>
-
-#ifdef NEW_SKBUFF
-#include <linux/netprotocol.h>
-#endif
-
-#include <netinet/ip.h>
-#include <netinet/tcp.h>
-#include <net/if_arp.h>
-
-#undef PACKETPTR
-#define PACKETPTR 1
#include <linux/ppp-comp.h>
-#undef PACKETPTR
#include "zlib.c"
#define DEFLATE_OVHD 2 /* Deflate overhead/packet */
static void *zalloc __P((void *, unsigned int items, unsigned int size));
+static void *zalloc_init __P((void *, unsigned int items,
+ unsigned int size));
static void zfree __P((void *, void *ptr, unsigned int nb));
static void *z_comp_alloc __P((unsigned char *options, int opt_len));
static void *z_decomp_alloc __P((unsigned char *options, int opt_len));
static void z_decomp_reset __P((void *state));
static void z_comp_stats __P((void *state, struct compstat *stats));
-/*
- * This is a small set of memory allocation routines. I created them so
- * that all memory allocation from the kernel takes place at the
- * z_(de)comp_alloc and z_(de)comp_free routines. This eliminates worry
- * about calling valloc() from within an interrupt.
- *
- * The free list is a single linked list sorted by memory address.
- * The zfree() function re-combines any segments it can.
- */
-typedef struct memchunk {
- unsigned int m_size;
- struct memchunk *m_next;
-} MemChunk;
-
-typedef struct {
- void *memHead;
- MemChunk *freePool;
-} MemPool;
-
-static int memPoolAlloc __P((void *arg, unsigned int size));
-static void memPoolFree __P((void *arg));
-
-static int
-memPoolAlloc(arg, size)
-void *arg;
-unsigned int size;
-{
- MemPool **memPool = arg;
- MemChunk *freePool;
-
- if ((*memPool = kmalloc(sizeof(MemPool), GFP_KERNEL)) == NULL) {
- printk(KERN_DEBUG "Unable to allocate Memory Head\n");
- return 0;
- }
-
- if (((*memPool)->memHead = (void *)vmalloc(size)) == NULL) {
- printk(KERN_DEBUG "Unable to allocate Memory Pool\n");
- kfree(*memPool);
- return 0;
- }
- freePool = (*memPool)->freePool = (*memPool)->memHead;
- freePool->m_size = size;
- freePool->m_next = 0;
-
- return 1;
-}
-
-static void
-memPoolFree(arg)
-void *arg;
-{
- MemPool **memPool = arg;
-
- if (*memPool) {
- vfree((*memPool)->memHead);
- kfree(*memPool);
- *memPool = NULL;
- }
-}
+struct chunk_header {
+ unsigned size; /* amount of space following header */
+ int valloced; /* allocated with valloc, not kmalloc */
+};
-#ifdef POOLDGB
-static void showFreeList __P((MemChunk *));
-
-static void
-showFreeList(freePool)
-MemChunk *freePool;
-{
- MemChunk *node;
-
- for (node = freePool; node; node = node->m_next)
- printk(KERN_DEBUG "{%x,%d}->", node, node->m_size);
- printk(KERN_DEBUG "\n");
-}
-#endif
+#define MIN_VMALLOC 2048 /* use kmalloc for blocks < this */
/*
* Space allocation and freeing routines for use by zlib routines.
void *ptr;
unsigned int nbytes;
{
- MemPool *memPool = (MemPool *)arg;
- MemChunk *mprev = 0, *node;
- MemChunk *new = (void *)(((unsigned char *)ptr) - sizeof(MemChunk));
+ struct chunk_header *hdr = ((struct chunk_header *)ptr) - 1;
- if (!memPool->freePool) {
- new->m_next = 0;
- memPool->freePool = new;
- } else {
- /*
- * Find where this new chunk fits in the free list.
- */
- for (node = memPool->freePool; node && new > node; node = node->m_next)
- mprev = node;
- /*
- * Re-combine with the following free chunk if possible.
- */
- if ((((unsigned char *)new) + new->m_size) == (unsigned char *)node) {
- new->m_size += node->m_size;
- new->m_next = node->m_next;
- if (mprev) {
- if ((((unsigned char *)mprev) + mprev->m_size) == (unsigned char *)new) {
- mprev->m_size += new->m_size;
- mprev->m_next = new->m_next;
- } else
- mprev->m_next = new;
- } else
- memPool->freePool = new;
- /*
- * Re-combine with the previous free chunk if possible.
- */
- } else if (mprev && (((unsigned char *)mprev) + mprev->m_size) ==
- (unsigned char *)new) {
- mprev->m_size += new->m_size;
- if ((((unsigned char *)mprev) + mprev->m_size) == (unsigned char *)node) {
- mprev->m_size += node->m_size;
- mprev->m_next = node->m_next;
- } else
- mprev->m_next = node;
- /*
- * No luck re-combining, just insert the new chunk into the list.
- */
- } else {
- if (mprev)
- mprev->m_next = new;
- else
- memPool->freePool = new;
- new->m_next = node;
- }
- }
+ if (hdr->valloced)
+ vfree(hdr);
+ else
+ kfree(hdr);
}
void *
void *arg;
unsigned int items, size;
{
- MemPool *memPool = (MemPool *)arg;
- MemChunk *mprev = 0, *node;
-
- size *= items;
- size += sizeof(MemChunk);
- if (size & 0x3)
- size = (size + 7) & ~3;
- for (node = memPool->freePool; node; node = node->m_next) {
- if (size == node->m_size) {
- if (mprev)
- mprev->m_next = node->m_next;
- else
- memPool->freePool = node->m_next;
- return (void *)(((unsigned char *)node)+sizeof(MemChunk));
- } else if (node->m_size > (size + sizeof(MemChunk) + 7)) {
- MemChunk *new;
-
- new = (void *)(((unsigned char *)node) + size);
- new->m_size = node->m_size - size;
- new->m_next = node->m_next;
- if (mprev)
- mprev->m_next = new;
- else
- memPool->freePool = new;
-
- node->m_size = size;
-
- return (void *)(((unsigned char *)node)+sizeof(MemChunk));
- break;
- }
- mprev = node;
- }
- printk(KERN_DEBUG
- "zalloc(%d)... Out of memory in Pool!\n", size - sizeof(MemChunk));
- return NULL;
+ struct chunk_header *hdr;
+ unsigned nbytes;
+
+ nbytes = items * size + sizeof(*hdr);
+ hdr = kmalloc(nbytes, GFP_ATOMIC);
+ if (hdr == 0)
+ return 0;
+ hdr->size = nbytes;
+ hdr->valloced = 0;
+ return (void *) (hdr + 1);
+}
+
+void *
+zalloc_init(arg, items, size)
+ void *arg;
+ unsigned int items, size;
+{
+ struct chunk_header *hdr;
+ unsigned nbytes;
+
+ nbytes = items * size + sizeof(*hdr);
+ if (nbytes >= MIN_VMALLOC)
+ hdr = vmalloc(nbytes);
+ else
+ hdr = kmalloc(nbytes, GFP_KERNEL);
+ if (hdr == 0)
+ return 0;
+ hdr->size = nbytes;
+ hdr->valloced = nbytes >= MIN_VMALLOC;
+ return (void *) (hdr + 1);
}
static void
if (state) {
deflateEnd(&state->strm);
- memPoolFree(&state->strm.opaque);
kfree(state);
MOD_DEC_USE_COUNT;
}
memset (state, 0, sizeof (struct ppp_deflate_state));
state->strm.next_in = NULL;
state->strm.zalloc = zalloc;
+ state->strm.zalloc_init = zalloc;
state->strm.zfree = zfree;
state->w_size = w_size;
- if (!memPoolAlloc(&state->strm.opaque, 0x50000)) {
- z_comp_free(state);
- return NULL;
- }
-
if (deflateInit2(&state->strm, Z_DEFAULT_COMPRESSION, DEFLATE_METHOD_VAL,
-w_size, 8, Z_DEFAULT_STRATEGY, DEFLATE_OVHD+2) != Z_OK) {
z_comp_free(state);
void *arg;
{
struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg;
+
state->seqno = 0;
deflateReset(&state->strm);
}
*/
proto = PPP_PROTOCOL(rptr);
if (proto > 0x3fff || proto == 0xfd || proto == 0xfb)
- return isize;
+ return 0;
/* Don't generate compressed packets which are larger than
the uncompressed packet. */
for (;;) {
r = deflate(&state->strm, Z_PACKET_FLUSH);
if (r != Z_OK) {
- printk(KERN_DEBUG "z_compress: deflate returned %d (%s)\n",
- r, (state->strm.msg? state->strm.msg: ""));
+ if (state->debug)
+ printk(KERN_DEBUG "z_compress: deflate returned %d (%s)\n",
+ r, (state->strm.msg? state->strm.msg: ""));
break;
}
if (state->strm.avail_out == 0) {
if (state) {
inflateEnd(&state->strm);
+#if USEMEMPOOL
memPoolFree(&state->strm.opaque);
+#endif
kfree(state);
MOD_DEC_USE_COUNT;
}
state->strm.zalloc = zalloc;
state->strm.zfree = zfree;
- if (!memPoolAlloc(&state->strm.opaque, 0x10000)) {
- z_decomp_free(state);
- return NULL;
- }
-
if (inflateInit2(&state->strm, -w_size) != Z_OK) {
z_decomp_free(state);
return NULL;
int osize;
{
struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg;
- int olen, seq, i, r, decode_proto;
- unsigned char hdr[PPP_HDRLEN + DEFLATE_OVHD];
- unsigned char *rptr, *wptr;
+ int olen, seq, r;
+ int decode_proto, overflow;
+ unsigned char overflow_buf[1];
- rptr = ibuf;
- wptr = obuf;
- for (i = 0; i < PPP_HDRLEN + DEFLATE_OVHD; ++i)
- hdr[i] = *rptr++;
+ if (isize <= PPP_HDRLEN + DEFLATE_OVHD) {
+ if (state->debug)
+ printk(KERN_DEBUG "z_decompress%d: short packet (len=%d)\n",
+ state->unit, isize);
+ return DECOMP_ERROR;
+ }
/* Check the sequence number. */
- seq = (hdr[PPP_HDRLEN] << 8) + hdr[PPP_HDRLEN+1];
+ seq = (ibuf[PPP_HDRLEN] << 8) + ibuf[PPP_HDRLEN+1];
if (seq != state->seqno) {
if (state->debug)
printk(KERN_DEBUG "z_decompress%d: bad seq # %d, expected %d\n",
* Fill in the first part of the PPP header. The protocol field
* comes from the decompressed data.
*/
- wptr[0] = PPP_ADDRESS(hdr);
- wptr[1] = PPP_CONTROL(hdr);
- wptr[2] = 0;
+ 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 = rptr;
+ state->strm.next_in = ibuf + PPP_HDRLEN + DEFLATE_OVHD;
state->strm.avail_in = isize - (PPP_HDRLEN + DEFLATE_OVHD);
- state->strm.next_out = wptr + 3;
+ 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.
}
if (state->strm.avail_out != 0)
break; /* all done */
- if (state->strm.avail_out == 0) {
- if (decode_proto) {
- state->strm.avail_out = osize - PPP_HDRLEN;
- if ((wptr[3] & 1) == 0) {
- /* 2-byte protocol field */
- wptr[2] = wptr[3];
- --state->strm.next_out;
- ++state->strm.avail_out;
- }
- decode_proto = 0;
- } else {
- if (state->debug)
- printk(KERN_DEBUG "z_decompress%d: ran out of mru\n",
- state->unit);
- return DECOMP_FATALERROR;
+ 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;
+ } else if (!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)
return DECOMP_ERROR;
- olen = (osize - state->strm.avail_out);
-
+ olen = osize + overflow - state->strm.avail_out;
state->stats.unc_bytes += olen;
state->stats.unc_packets++;
state->stats.comp_bytes += isize;
int icnt;
{
struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg;
- unsigned char *rptr = ibuf;
int proto, r;
/*
* Check that the protocol is one we handle.
*/
- proto = PPP_PROTOCOL(rptr);
+ proto = PPP_PROTOCOL(ibuf);
if (proto > 0x3fff || proto == 0xfd || proto == 0xfb)
return;
* at the either the 1st or 2nd byte of the protocol field,
* depending on whether the protocol value is compressible.
*/
- state->strm.next_in = rptr + 3;
+ state->strm.next_in = ibuf + 3;
state->strm.avail_in = icnt - 3;
if (proto > 0xff) {
--state->strm.next_in;
z_comp_stats, /* decomp_stat */
};
+#ifdef MODULE
/*************************************************************
* Module support routines
*************************************************************/
else
ppp_unregister_compressor (&ppp_deflate);
}
+#endif