source: rtems/cpukit/libnetworking/net/bsd-comp.c @ 4c672b93

4.104.114.84.95
Last change on this file since 4c672b93 was 0286b9f, checked in by Joel Sherrill <joel.sherrill@…>, on 01/31/02 at 21:42:11

2001-01-31 Mike Siers <mikes@…>

  • Nice Update of PPPD support which eliminates the requiremetn that drivers be in the termios TASK_DRIVEN mode. Mike did significant testing and reports that it seems to be more stable and handle larger packets better. This patch replaces the termios tasks with more general pppd network driver tasks. The functions pppinput() and pppstart() get called from the interrupt service routine.
  • Makefile.am, configure.ac, net/Makefile.am, net/bpf.h, net/ethernet.h, net/if.c, net/if.h, net/if_arp.h, net/if_dl.h, net/if_ethersubr.c, net/if_llc.h, net/if_loop.c, net/if_ppp.h, net/if_pppvar.h, net/if_types.h, net/netisr.h, net/ppp-comp.h, net/ppp_defs.h, net/pppcompress.h, net/radix.c, net/radix.h, net/raw_cb.c, net/raw_cb.h, net/raw_usrreq.c, net/route.c, net/route.h, net/rtsock.c, pppd/Makefile.am, pppd/README, pppd/STATUS, pppd/auth.c, pppd/cbcp.c, pppd/ccp.c, pppd/ccp.h, pppd/chap.c, pppd/chap.h, pppd/chap_ms.c, pppd/chap_ms.h, pppd/chat.c, pppd/demand.c, pppd/fsm.c, pppd/fsm.h, pppd/ipcp.c, pppd/ipcp.h, pppd/ipxcp.c, pppd/ipxcp.h, pppd/lcp.c, pppd/lcp.h, pppd/magic.c, pppd/magic.h, pppd/options.c, pppd/patchlevel.h, pppd/pathnames.h, pppd/pppd.8, pppd/pppd.h, pppd/rtemsmain.c, pppd/rtemspppd.c, pppd/rtemspppd.h, pppd/sys-rtems.c, pppd/upap.c, pppd/upap.h, pppd/utils.c, pppd/example/README, pppd/example/netconfig.h, wrapup/Makefile.am: Modified.
  • net/bsd-comp.c, net/if_ppp.c, net/ppp-deflate.c, net/ppp.h, net/ppp_tty.c, net/pppcompress.c, net/zlib.c, net/zlib.h: New file.
  • modem/, modem/.cvsignore, modem/Makefile.am, modem/ppp.c, modem/ppp.h, modem/ppp_tty.c, modem/pppcompress.c: Subdirectory removed.
  • Property mode set to 100644
File size: 29.2 KB
Line 
1/*      $Id$    */
2
3/* Because this code is derived from the 4.3BSD compress source:
4 *
5 *
6 * Copyright (c) 1985, 1986 The Regents of the University of California.
7 * All rights reserved.
8 *
9 * This code is derived from software contributed to Berkeley by
10 * James A. Woods, derived from original work by Spencer Thomas
11 * and Joseph Orost.
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 * 1. Redistributions of source code must retain the above copyright
17 *    notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 *    notice, this list of conditions and the following disclaimer in the
20 *    documentation and/or other materials provided with the distribution.
21 * 3. All advertising materials mentioning features or use of this software
22 *    must display the following acknowledgement:
23 *      This product includes software developed by the University of
24 *      California, Berkeley and its contributors.
25 * 4. Neither the name of the University nor the names of its contributors
26 *    may be used to endorse or promote products derived from this software
27 *    without specific prior written permission.
28 *
29 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
30 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
33 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39 * SUCH DAMAGE.
40 */
41
42/*
43 * This version is for use with mbufs on BSD-derived systems.
44 */
45
46#include <sys/param.h>
47#include <sys/types.h>
48#include <sys/systm.h>
49#include <sys/mbuf.h>
50#include <sys/socket.h>
51#include <net/if.h>
52#include <net/if_types.h>
53#include <net/ppp_defs.h>
54#include <net/if_ppp.h>
55
56#define PACKETPTR       struct mbuf *
57#include <net/ppp-comp.h>
58
59#if DO_BSD_COMPRESS
60/*
61 * PPP "BSD compress" compression
62 *  The differences between this compression and the classic BSD LZW
63 *  source are obvious from the requirement that the classic code worked
64 *  with files while this handles arbitrarily long streams that
65 *  are broken into packets.  They are:
66 *
67 *      When the code size expands, a block of junk is not emitted by
68 *          the compressor and not expected by the decompressor.
69 *
70 *      New codes are not necessarily assigned every time an old
71 *          code is output by the compressor.  This is because a packet
72 *          end forces a code to be emitted, but does not imply that a
73 *          new sequence has been seen.
74 *
75 *      The compression ratio is checked at the first end of a packet
76 *          after the appropriate gap.  Besides simplifying and speeding
77 *          things up, this makes it more likely that the transmitter
78 *          and receiver will agree when the dictionary is cleared when
79 *          compression is not going well.
80 */
81
82/*
83 * A dictionary for doing BSD compress.
84 */
85struct bsd_db {
86    int     totlen;                     /* length of this structure */
87    u_int   hsize;                      /* size of the hash table */
88    u_char  hshift;                     /* used in hash function */
89    u_char  n_bits;                     /* current bits/code */
90    u_char  maxbits;
91    u_char  debug;
92    u_char  unit;
93    u_int16_t seqno;                    /* sequence # of next packet */
94    u_int   hdrlen;                     /* header length to preallocate */
95    u_int   mru;
96    u_int   maxmaxcode;                 /* largest valid code */
97    u_int   max_ent;                    /* largest code in use */
98    u_int   in_count;                   /* uncompressed bytes, aged */
99    u_int   bytes_out;                  /* compressed bytes, aged */
100    u_int   ratio;                      /* recent compression ratio */
101    u_int   checkpoint;                 /* when to next check the ratio */
102    u_int   clear_count;                /* times dictionary cleared */
103    u_int   incomp_count;               /* incompressible packets */
104    u_int   incomp_bytes;               /* incompressible bytes */
105    u_int   uncomp_count;               /* uncompressed packets */
106    u_int   uncomp_bytes;               /* uncompressed bytes */
107    u_int   comp_count;                 /* compressed packets */
108    u_int   comp_bytes;                 /* compressed bytes */
109    u_int16_t *lens;                    /* array of lengths of codes */
110    struct bsd_dict {
111        union {                         /* hash value */
112            u_int32_t   fcode;
113            struct {
114#if BYTE_ORDER == LITTLE_ENDIAN
115                u_int16_t prefix;       /* preceding code */
116                u_char  suffix;         /* last character of new code */
117                u_char  pad;
118#else
119                u_char  pad;
120                u_char  suffix;         /* last character of new code */
121                u_int16_t prefix;       /* preceding code */
122#endif
123            } hs;
124        } f;
125        u_int16_t codem1;               /* output of hash table -1 */
126        u_int16_t cptr;                 /* map code to hash table entry */
127    } dict[1];
128};
129
130#define BSD_OVHD        2               /* BSD compress overhead/packet */
131#define BSD_INIT_BITS   BSD_MIN_BITS
132
133static void     *bsd_comp_alloc __P((u_char *options, int opt_len));
134static void     *bsd_decomp_alloc __P((u_char *options, int opt_len));
135static void     bsd_free __P((void *state));
136static int      bsd_comp_init __P((void *state, u_char *options, int opt_len,
137                                   int unit, int hdrlen, int debug));
138static int      bsd_decomp_init __P((void *state, u_char *options, int opt_len,
139                                     int unit, int hdrlen, int mru, int debug));
140static int      bsd_compress __P((void *state, struct mbuf **mret,
141                                  struct mbuf *mp, int slen, int maxolen));
142static void     bsd_incomp __P((void *state, struct mbuf *dmsg));
143static int      bsd_decompress __P((void *state, struct mbuf *cmp,
144                                    struct mbuf **dmpp));
145static void     bsd_reset __P((void *state));
146static void     bsd_comp_stats __P((void *state, struct compstat *stats));
147
148/*
149 * Procedures exported to if_ppp.c.
150 */
151struct compressor ppp_bsd_compress = {
152    CI_BSD_COMPRESS,            /* compress_proto */
153    bsd_comp_alloc,             /* comp_alloc */
154    bsd_free,                   /* comp_free */
155    bsd_comp_init,              /* comp_init */
156    bsd_reset,                  /* comp_reset */
157    bsd_compress,               /* compress */
158    bsd_comp_stats,             /* comp_stat */
159    bsd_decomp_alloc,           /* decomp_alloc */
160    bsd_free,                   /* decomp_free */
161    bsd_decomp_init,            /* decomp_init */
162    bsd_reset,                  /* decomp_reset */
163    bsd_decompress,             /* decompress */
164    bsd_incomp,                 /* incomp */
165    bsd_comp_stats,             /* decomp_stat */
166};
167
168/*
169 * the next two codes should not be changed lightly, as they must not
170 * lie within the contiguous general code space.
171 */
172#define CLEAR   256                     /* table clear output code */
173#define FIRST   257                     /* first free entry */
174#define LAST    255
175
176#define MAXCODE(b)      ((1 << (b)) - 1)
177#define BADCODEM1       MAXCODE(BSD_MAX_BITS)
178
179#define BSD_HASH(prefix,suffix,hshift)  ((((u_int32_t)(suffix)) << (hshift)) \
180                                         ^ (u_int32_t)(prefix))
181#define BSD_KEY(prefix,suffix)          ((((u_int32_t)(suffix)) << 16) \
182                                         + (u_int32_t)(prefix))
183
184#define CHECK_GAP       10000           /* Ratio check interval */
185
186#define RATIO_SCALE_LOG 8
187#define RATIO_SCALE     (1<<RATIO_SCALE_LOG)
188#define RATIO_MAX       (0x7fffffff>>RATIO_SCALE_LOG)
189
190static void bsd_clear __P((struct bsd_db *));
191static int bsd_check __P((struct bsd_db *));
192static void *bsd_alloc __P((u_char *, int, int));
193static int bsd_init __P((struct bsd_db *, u_char *, int, int, int, int,
194                         int, int));
195
196/*
197 * clear the dictionary
198 */
199static void
200bsd_clear(db)
201    struct bsd_db *db;
202{
203    db->clear_count++;
204    db->max_ent = FIRST-1;
205    db->n_bits = BSD_INIT_BITS;
206    db->ratio = 0;
207    db->bytes_out = 0;
208    db->in_count = 0;
209    db->checkpoint = CHECK_GAP;
210}
211
212/*
213 * If the dictionary is full, then see if it is time to reset it.
214 *
215 * Compute the compression ratio using fixed-point arithmetic
216 * with 8 fractional bits.
217 *
218 * Since we have an infinite stream instead of a single file,
219 * watch only the local compression ratio.
220 *
221 * Since both peers must reset the dictionary at the same time even in
222 * the absence of CLEAR codes (while packets are incompressible), they
223 * must compute the same ratio.
224 */
225static int                              /* 1=output CLEAR */
226bsd_check(db)
227    struct bsd_db *db;
228{
229    u_int new_ratio;
230
231    if (db->in_count >= db->checkpoint) {
232        /* age the ratio by limiting the size of the counts */
233        if (db->in_count >= RATIO_MAX
234            || db->bytes_out >= RATIO_MAX) {
235            db->in_count -= db->in_count/4;
236            db->bytes_out -= db->bytes_out/4;
237        }
238
239        db->checkpoint = db->in_count + CHECK_GAP;
240
241        if (db->max_ent >= db->maxmaxcode) {
242            /* Reset the dictionary only if the ratio is worse,
243             * or if it looks as if it has been poisoned
244             * by incompressible data.
245             *
246             * This does not overflow, because
247             *  db->in_count <= RATIO_MAX.
248             */
249            new_ratio = db->in_count << RATIO_SCALE_LOG;
250            if (db->bytes_out != 0)
251                new_ratio /= db->bytes_out;
252
253            if (new_ratio < db->ratio || new_ratio < 1 * RATIO_SCALE) {
254                bsd_clear(db);
255                return 1;
256            }
257            db->ratio = new_ratio;
258        }
259    }
260    return 0;
261}
262
263/*
264 * Return statistics.
265 */
266static void
267bsd_comp_stats(state, stats)
268    void *state;
269    struct compstat *stats;
270{
271    struct bsd_db *db = (struct bsd_db *) state;
272    u_int out;
273
274    stats->unc_bytes = db->uncomp_bytes;
275    stats->unc_packets = db->uncomp_count;
276    stats->comp_bytes = db->comp_bytes;
277    stats->comp_packets = db->comp_count;
278    stats->inc_bytes = db->incomp_bytes;
279    stats->inc_packets = db->incomp_count;
280    stats->ratio = db->in_count;
281    out = db->bytes_out;
282    if (stats->ratio <= 0x7fffff)
283        stats->ratio <<= 8;
284    else
285        out >>= 8;
286    if (out != 0)
287        stats->ratio /= out;
288}
289
290/*
291 * Reset state, as on a CCP ResetReq.
292 */
293static void
294bsd_reset(state)
295    void *state;
296{
297    struct bsd_db *db = (struct bsd_db *) state;
298
299    db->seqno = 0;
300    bsd_clear(db);
301    db->clear_count = 0;
302}
303
304/*
305 * Allocate space for a (de) compressor.
306 */
307static void *
308bsd_alloc(options, opt_len, decomp)
309    u_char *options;
310    int opt_len, decomp;
311{
312    int bits;
313    u_int newlen, hsize, hshift, maxmaxcode;
314    struct bsd_db *db;
315
316    if (opt_len < CILEN_BSD_COMPRESS || options[0] != CI_BSD_COMPRESS
317        || options[1] != CILEN_BSD_COMPRESS
318        || BSD_VERSION(options[2]) != BSD_CURRENT_VERSION)
319        return NULL;
320    bits = BSD_NBITS(options[2]);
321    switch (bits) {
322    case 9:                     /* needs 82152 for both directions */
323    case 10:                    /* needs 84144 */
324    case 11:                    /* needs 88240 */
325    case 12:                    /* needs 96432 */
326        hsize = 5003;
327        hshift = 4;
328        break;
329    case 13:                    /* needs 176784 */
330        hsize = 9001;
331        hshift = 5;
332        break;
333    case 14:                    /* needs 353744 */
334        hsize = 18013;
335        hshift = 6;
336        break;
337    case 15:                    /* needs 691440 */
338        hsize = 35023;
339        hshift = 7;
340        break;
341    case 16:                    /* needs 1366160--far too much, */
342        /* hsize = 69001; */    /* and 69001 is too big for cptr */
343        /* hshift = 8; */       /* in struct bsd_db */
344        /* break; */
345    default:
346        return NULL;
347    }
348
349    maxmaxcode = MAXCODE(bits);
350    newlen = sizeof(*db) + (hsize-1) * (sizeof(db->dict[0]));
351    MALLOC(db, struct bsd_db *, newlen, M_DEVBUF, M_NOWAIT);
352    if (!db)
353        return NULL;
354    bzero(db, sizeof(*db) - sizeof(db->dict));
355
356    if (!decomp) {
357        db->lens = NULL;
358    } else {
359        MALLOC(db->lens, u_int16_t *, (maxmaxcode+1) * sizeof(db->lens[0]),
360               M_DEVBUF, M_NOWAIT);
361        if (!db->lens) {
362            FREE(db, M_DEVBUF);
363            return NULL;
364        }
365    }
366
367    db->totlen = newlen;
368    db->hsize = hsize;
369    db->hshift = hshift;
370    db->maxmaxcode = maxmaxcode;
371    db->maxbits = bits;
372
373    return (void *) db;
374}
375
376static void
377bsd_free(state)
378    void *state;
379{
380    struct bsd_db *db = (struct bsd_db *) state;
381
382    if (db->lens)
383        FREE(db->lens, M_DEVBUF);
384    FREE(db, M_DEVBUF);
385}
386
387static void *
388bsd_comp_alloc(options, opt_len)
389    u_char *options;
390    int opt_len;
391{
392    return bsd_alloc(options, opt_len, 0);
393}
394
395static void *
396bsd_decomp_alloc(options, opt_len)
397    u_char *options;
398    int opt_len;
399{
400    return bsd_alloc(options, opt_len, 1);
401}
402
403/*
404 * Initialize the database.
405 */
406static int
407bsd_init(db, options, opt_len, unit, hdrlen, mru, debug, decomp)
408    struct bsd_db *db;
409    u_char *options;
410    int opt_len, unit, hdrlen, mru, debug, decomp;
411{
412    int i;
413
414    if (opt_len < CILEN_BSD_COMPRESS || options[0] != CI_BSD_COMPRESS
415        || options[1] != CILEN_BSD_COMPRESS
416        || BSD_VERSION(options[2]) != BSD_CURRENT_VERSION
417        || BSD_NBITS(options[2]) != db->maxbits
418        || (decomp && db->lens == NULL))
419        return 0;
420
421    if (decomp) {
422        i = LAST+1;
423        while (i != 0)
424            db->lens[--i] = 1;
425    }
426    i = db->hsize;
427    while (i != 0) {
428        db->dict[--i].codem1 = BADCODEM1;
429        db->dict[i].cptr = 0;
430    }
431
432    db->unit = unit;
433    db->hdrlen = hdrlen;
434    db->mru = mru;
435#ifndef DEBUG
436    if (debug)
437#endif
438        db->debug = 1;
439
440    bsd_reset(db);
441
442    return 1;
443}
444
445static int
446bsd_comp_init(state, options, opt_len, unit, hdrlen, debug)
447    void *state;
448    u_char *options;
449    int opt_len, unit, hdrlen, debug;
450{
451    return bsd_init((struct bsd_db *) state, options, opt_len,
452                    unit, hdrlen, 0, debug, 0);
453}
454
455static int
456bsd_decomp_init(state, options, opt_len, unit, hdrlen, mru, debug)
457    void *state;
458    u_char *options;
459    int opt_len, unit, hdrlen, mru, debug;
460{
461    return bsd_init((struct bsd_db *) state, options, opt_len,
462                    unit, hdrlen, mru, debug, 1);
463}
464
465
466/*
467 * compress a packet
468 *      One change from the BSD compress command is that when the
469 *      code size expands, we do not output a bunch of padding.
470 */
471int                                     /* new slen */
472bsd_compress(state, mret, mp, slen, maxolen)
473    void *state;
474    struct mbuf **mret;         /* return compressed mbuf chain here */
475    struct mbuf *mp;            /* from here */
476    int slen;                   /* uncompressed length */
477    int maxolen;                /* max compressed length */
478{
479    struct bsd_db *db = (struct bsd_db *) state;
480    int hshift = db->hshift;
481    u_int max_ent = db->max_ent;
482    u_int n_bits = db->n_bits;
483    u_int bitno = 32;
484    u_int32_t accm = 0, fcode;
485    struct bsd_dict *dictp;
486    u_char c;
487    int hval, disp, ent, ilen;
488    u_char *rptr, *wptr;
489    u_char *cp_end;
490    int olen;
491    struct mbuf *m;
492
493#define PUTBYTE(v) {                                    \
494    ++olen;                                             \
495    if (wptr) {                                         \
496        *wptr++ = (v);                                  \
497        if (wptr >= cp_end) {                           \
498            m->m_len = wptr - mtod(m, u_char *);        \
499            MGET(m->m_next, M_DONTWAIT, MT_DATA);       \
500            m = m->m_next;                              \
501            if (m) {                                    \
502                m->m_len = 0;                           \
503                if (maxolen - olen > MLEN)              \
504                    MCLGET(m, M_DONTWAIT);              \
505                wptr = mtod(m, u_char *);               \
506                cp_end = wptr + M_TRAILINGSPACE(m);     \
507            } else                                      \
508                wptr = NULL;                            \
509        }                                               \
510    }                                                   \
511}
512
513#define OUTPUT(ent) {                                   \
514    bitno -= n_bits;                                    \
515    accm |= ((ent) << bitno);                           \
516    do {                                                \
517        PUTBYTE(accm >> 24);                            \
518        accm <<= 8;                                     \
519        bitno += 8;                                     \
520    } while (bitno <= 24);                              \
521}
522
523    /*
524     * If the protocol is not in the range we're interested in,
525     * just return without compressing the packet.  If it is,
526     * the protocol becomes the first byte to compress.
527     */
528    rptr = mtod(mp, u_char *);
529    ent = PPP_PROTOCOL(rptr);
530    if (ent < 0x21 || ent > 0xf9) {
531        *mret = NULL;
532        return slen;
533    }
534
535    /* Don't generate compressed packets which are larger than
536       the uncompressed packet. */
537    if (maxolen > slen)
538        maxolen = slen;
539
540    /* Allocate one mbuf to start with. */
541    MGET(m, M_DONTWAIT, MT_DATA);
542    *mret = m;
543    if (m != NULL) {
544        m->m_len = 0;
545        if (maxolen + db->hdrlen > MLEN)
546            MCLGET(m, M_DONTWAIT);
547        m->m_data += db->hdrlen;
548        wptr = mtod(m, u_char *);
549        cp_end = wptr + M_TRAILINGSPACE(m);
550    } else
551        wptr = cp_end = NULL;
552
553    /*
554     * Copy the PPP header over, changing the protocol,
555     * and install the 2-byte packet sequence number.
556     */
557    if (wptr) {
558        *wptr++ = PPP_ADDRESS(rptr);    /* assumes the ppp header is */
559        *wptr++ = PPP_CONTROL(rptr);    /* all in one mbuf */
560        *wptr++ = 0;                    /* change the protocol */
561        *wptr++ = PPP_COMP;
562        *wptr++ = db->seqno >> 8;
563        *wptr++ = db->seqno;
564    }
565    ++db->seqno;
566
567    olen = 0;
568    rptr += PPP_HDRLEN;
569    slen = mp->m_len - PPP_HDRLEN;
570    ilen = slen + 1;
571    for (;;) {
572        if (slen <= 0) {
573            mp = mp->m_next;
574            if (!mp)
575                break;
576            rptr = mtod(mp, u_char *);
577            slen = mp->m_len;
578            if (!slen)
579                continue;   /* handle 0-length buffers */
580            ilen += slen;
581        }
582
583        slen--;
584        c = *rptr++;
585        fcode = BSD_KEY(ent, c);
586        hval = BSD_HASH(ent, c, hshift);
587        dictp = &db->dict[hval];
588
589        /* Validate and then check the entry. */
590        if (dictp->codem1 >= max_ent)
591            goto nomatch;
592        if (dictp->f.fcode == fcode) {
593            ent = dictp->codem1+1;
594            continue;   /* found (prefix,suffix) */
595        }
596
597        /* continue probing until a match or invalid entry */
598        disp = (hval == 0) ? 1 : hval;
599        do {
600            hval += disp;
601            if (hval >= db->hsize)
602                hval -= db->hsize;
603            dictp = &db->dict[hval];
604            if (dictp->codem1 >= max_ent)
605                goto nomatch;
606        } while (dictp->f.fcode != fcode);
607        ent = dictp->codem1 + 1;        /* finally found (prefix,suffix) */
608        continue;
609
610    nomatch:
611        OUTPUT(ent);            /* output the prefix */
612
613        /* code -> hashtable */
614        if (max_ent < db->maxmaxcode) {
615            struct bsd_dict *dictp2;
616            /* expand code size if needed */
617            if (max_ent >= MAXCODE(n_bits))
618                db->n_bits = ++n_bits;
619
620            /* Invalidate old hash table entry using
621             * this code, and then take it over.
622             */
623            dictp2 = &db->dict[max_ent+1];
624            if (db->dict[dictp2->cptr].codem1 == max_ent)
625                db->dict[dictp2->cptr].codem1 = BADCODEM1;
626            dictp2->cptr = hval;
627            dictp->codem1 = max_ent;
628            dictp->f.fcode = fcode;
629
630            db->max_ent = ++max_ent;
631        }
632        ent = c;
633    }
634
635    OUTPUT(ent);                /* output the last code */
636    db->bytes_out += olen;
637    db->in_count += ilen;
638    if (bitno < 32)
639        ++db->bytes_out;        /* count complete bytes */
640
641    if (bsd_check(db))
642        OUTPUT(CLEAR);          /* do not count the CLEAR */
643
644    /*
645     * Pad dribble bits of last code with ones.
646     * Do not emit a completely useless byte of ones.
647     */
648    if (bitno != 32)
649        PUTBYTE((accm | (0xff << (bitno-8))) >> 24);
650
651    if (m != NULL) {
652        m->m_len = wptr - mtod(m, u_char *);
653        m->m_next = NULL;
654    }
655
656    /*
657     * Increase code size if we would have without the packet
658     * boundary and as the decompressor will.
659     */
660    if (max_ent >= MAXCODE(n_bits) && max_ent < db->maxmaxcode)
661        db->n_bits++;
662
663    db->uncomp_bytes += ilen;
664    ++db->uncomp_count;
665    if (olen + PPP_HDRLEN + BSD_OVHD > maxolen) {
666        /* throw away the compressed stuff if it is longer than uncompressed */
667        if (*mret != NULL) {
668            m_freem(*mret);
669            *mret = NULL;
670        }
671        ++db->incomp_count;
672        db->incomp_bytes += ilen;
673    } else {
674        ++db->comp_count;
675        db->comp_bytes += olen + BSD_OVHD;
676    }
677
678    return olen + PPP_HDRLEN + BSD_OVHD;
679#undef OUTPUT
680#undef PUTBYTE
681}
682
683
684/*
685 * Update the "BSD Compress" dictionary on the receiver for
686 * incompressible data by pretending to compress the incoming data.
687 */
688static void
689bsd_incomp(state, dmsg)
690    void *state;
691    struct mbuf *dmsg;
692{
693    struct bsd_db *db = (struct bsd_db *) state;
694    u_int hshift = db->hshift;
695    u_int max_ent = db->max_ent;
696    u_int n_bits = db->n_bits;
697    struct bsd_dict *dictp;
698    u_int32_t fcode;
699    u_char c;
700    u_int32_t hval, disp;
701    int slen, ilen;
702    u_int bitno = 7;
703    u_char *rptr;
704    u_int ent;
705
706    /*
707     * If the protocol is not in the range we're interested in,
708     * just return without looking at the packet.  If it is,
709     * the protocol becomes the first byte to "compress".
710     */
711    rptr = mtod(dmsg, u_char *);
712    ent = PPP_PROTOCOL(rptr);
713    if (ent < 0x21 || ent > 0xf9)
714        return;
715
716    db->seqno++;
717    ilen = 1;           /* count the protocol as 1 byte */
718    rptr += PPP_HDRLEN;
719    slen = dmsg->m_len - PPP_HDRLEN;
720    for (;;) {
721        if (slen <= 0) {
722            dmsg = dmsg->m_next;
723            if (!dmsg)
724                break;
725            rptr = mtod(dmsg, u_char *);
726            slen = dmsg->m_len;
727            continue;
728        }
729        ilen += slen;
730
731        do {
732            c = *rptr++;
733            fcode = BSD_KEY(ent, c);
734            hval = BSD_HASH(ent, c, hshift);
735            dictp = &db->dict[hval];
736
737            /* validate and then check the entry */
738            if (dictp->codem1 >= max_ent)
739                goto nomatch;
740            if (dictp->f.fcode == fcode) {
741                ent = dictp->codem1+1;
742                continue;   /* found (prefix,suffix) */
743            }
744
745            /* continue probing until a match or invalid entry */
746            disp = (hval == 0) ? 1 : hval;
747            do {
748                hval += disp;
749                if (hval >= db->hsize)
750                    hval -= db->hsize;
751                dictp = &db->dict[hval];
752                if (dictp->codem1 >= max_ent)
753                    goto nomatch;
754            } while (dictp->f.fcode != fcode);
755            ent = dictp->codem1+1;
756            continue;   /* finally found (prefix,suffix) */
757
758        nomatch:                /* output (count) the prefix */
759            bitno += n_bits;
760
761            /* code -> hashtable */
762            if (max_ent < db->maxmaxcode) {
763                struct bsd_dict *dictp2;
764                /* expand code size if needed */
765                if (max_ent >= MAXCODE(n_bits))
766                    db->n_bits = ++n_bits;
767
768                /* Invalidate previous hash table entry
769                 * assigned this code, and then take it over.
770                 */
771                dictp2 = &db->dict[max_ent+1];
772                if (db->dict[dictp2->cptr].codem1 == max_ent)
773                    db->dict[dictp2->cptr].codem1 = BADCODEM1;
774                dictp2->cptr = hval;
775                dictp->codem1 = max_ent;
776                dictp->f.fcode = fcode;
777
778                db->max_ent = ++max_ent;
779                db->lens[max_ent] = db->lens[ent]+1;
780            }
781            ent = c;
782        } while (--slen != 0);
783    }
784    bitno += n_bits;            /* output (count) the last code */
785    db->bytes_out += bitno/8;
786    db->in_count += ilen;
787    (void)bsd_check(db);
788
789    ++db->incomp_count;
790    db->incomp_bytes += ilen;
791    ++db->uncomp_count;
792    db->uncomp_bytes += ilen;
793
794    /* Increase code size if we would have without the packet
795     * boundary and as the decompressor will.
796     */
797    if (max_ent >= MAXCODE(n_bits) && max_ent < db->maxmaxcode)
798        db->n_bits++;
799}
800
801
802/*
803 * Decompress "BSD Compress".
804 *
805 * Because of patent problems, we return DECOMP_ERROR for errors
806 * found by inspecting the input data and for system problems, but
807 * DECOMP_FATALERROR for any errors which could possibly be said to
808 * be being detected "after" decompression.  For DECOMP_ERROR,
809 * we can issue a CCP reset-request; for DECOMP_FATALERROR, we may be
810 * infringing a patent of Motorola's if we do, so we take CCP down
811 * instead.
812 *
813 * Given that the frame has the correct sequence number and a good FCS,
814 * errors such as invalid codes in the input most likely indicate a
815 * bug, so we return DECOMP_FATALERROR for them in order to turn off
816 * compression, even though they are detected by inspecting the input.
817 */
818int
819bsd_decompress(state, cmp, dmpp)
820    void *state;
821    struct mbuf *cmp, **dmpp;
822{
823    struct bsd_db *db = (struct bsd_db *) state;
824    u_int max_ent = db->max_ent;
825    u_int32_t accm = 0;
826    u_int bitno = 32;           /* 1st valid bit in accm */
827    u_int n_bits = db->n_bits;
828    u_int tgtbitno = 32-n_bits; /* bitno when we have a code */
829    struct bsd_dict *dictp;
830    int explen, i, seq, len;
831    u_int incode, oldcode, finchar;
832    u_char *p, *rptr, *wptr;
833    struct mbuf *m, *dmp, *mret;
834    int adrs, ctrl, ilen;
835    int space, codelen, extra;
836
837    /*
838     * Save the address/control from the PPP header
839     * and then get the sequence number.
840     */
841    *dmpp = NULL;
842    rptr = mtod(cmp, u_char *);
843    adrs = PPP_ADDRESS(rptr);
844    ctrl = PPP_CONTROL(rptr);
845    rptr += PPP_HDRLEN;
846    len = cmp->m_len - PPP_HDRLEN;
847    seq = 0;
848    for (i = 0; i < 2; ++i) {
849        while (len <= 0) {
850            cmp = cmp->m_next;
851            if (cmp == NULL)
852                return DECOMP_ERROR;
853            rptr = mtod(cmp, u_char *);
854            len = cmp->m_len;
855        }
856        seq = (seq << 8) + *rptr++;
857        --len;
858    }
859
860    /*
861     * Check the sequence number and give up if it differs from
862     * the value we're expecting.
863     */
864    if (seq != db->seqno) {
865        if (db->debug)
866            printf("bsd_decomp%d: bad sequence # %d, expected %d\n",
867                   db->unit, seq, db->seqno - 1);
868        return DECOMP_ERROR;
869    }
870    ++db->seqno;
871
872    /*
873     * Allocate one mbuf to start with.
874     */
875    MGETHDR(dmp, M_DONTWAIT, MT_DATA);
876    if (dmp == NULL)
877        return DECOMP_ERROR;
878    mret = dmp;
879    dmp->m_len = 0;
880    dmp->m_next = NULL;
881    MCLGET(dmp, M_DONTWAIT);
882    dmp->m_data += db->hdrlen;
883    wptr = mtod(dmp, u_char *);
884    space = M_TRAILINGSPACE(dmp) - PPP_HDRLEN + 1;
885
886    /*
887     * Fill in the ppp header, but not the last byte of the protocol
888     * (that comes from the decompressed data).
889     */
890    wptr[0] = adrs;
891    wptr[1] = ctrl;
892    wptr[2] = 0;
893    wptr += PPP_HDRLEN - 1;
894
895    ilen = len;
896    oldcode = CLEAR;
897    explen = 0;
898    for (;;) {
899        if (len == 0) {
900            cmp = cmp->m_next;
901            if (!cmp)           /* quit at end of message */
902                break;
903            rptr = mtod(cmp, u_char *);
904            len = cmp->m_len;
905            ilen += len;
906            continue;           /* handle 0-length buffers */
907        }
908
909        /*
910         * Accumulate bytes until we have a complete code.
911         * Then get the next code, relying on the 32-bit,
912         * unsigned accm to mask the result.
913         */
914        bitno -= 8;
915        accm |= *rptr++ << bitno;
916        --len;
917        if (tgtbitno < bitno)
918            continue;
919        incode = accm >> tgtbitno;
920        accm <<= n_bits;
921        bitno += n_bits;
922
923        if (incode == CLEAR) {
924            /*
925             * The dictionary must only be cleared at
926             * the end of a packet.  But there could be an
927             * empty mbuf at the end.
928             */
929            if (len > 0 || cmp->m_next != NULL) {
930                while ((cmp = cmp->m_next) != NULL)
931                    len += cmp->m_len;
932                if (len > 0) {
933                    m_freem(mret);
934                    if (db->debug)
935                        printf("bsd_decomp%d: bad CLEAR\n", db->unit);
936                    return DECOMP_FATALERROR;   /* probably a bug */
937                }
938            }
939            bsd_clear(db);
940            explen = ilen = 0;
941            break;
942        }
943
944        if (incode > max_ent + 2 || incode > db->maxmaxcode
945            || (incode > max_ent && oldcode == CLEAR)) {
946            m_freem(mret);
947            if (db->debug) {
948                printf("bsd_decomp%d: bad code 0x%x oldcode=0x%x ",
949                       db->unit, incode, oldcode);
950                printf("max_ent=0x%x explen=%d seqno=%d\n",
951                       max_ent, explen, db->seqno);
952            }
953            return DECOMP_FATALERROR;   /* probably a bug */
954        }
955
956        /* Special case for KwKwK string. */
957        if (incode > max_ent) {
958            finchar = oldcode;
959            extra = 1;
960        } else {
961            finchar = incode;
962            extra = 0;
963        }
964
965        codelen = db->lens[finchar];
966        explen += codelen + extra;
967        if (explen > db->mru + 1) {
968            m_freem(mret);
969            if (db->debug) {
970                printf("bsd_decomp%d: ran out of mru\n", db->unit);
971#ifdef DEBUG
972                while ((cmp = cmp->m_next) != NULL)
973                    len += cmp->m_len;
974                printf("  len=%d, finchar=0x%x, codelen=%d, explen=%d\n",
975                       len, finchar, codelen, explen);
976#endif
977            }
978            return DECOMP_FATALERROR;
979        }
980
981        /*
982         * For simplicity, the decoded characters go in a single mbuf,
983         * so we allocate a single extra cluster mbuf if necessary.
984         */
985        if ((space -= codelen + extra) < 0) {
986            dmp->m_len = wptr - mtod(dmp, u_char *);
987            MGET(m, M_DONTWAIT, MT_DATA);
988            if (m == NULL) {
989                m_freem(mret);
990                return DECOMP_ERROR;
991            }
992            m->m_len = 0;
993            m->m_next = NULL;
994            dmp->m_next = m;
995            MCLGET(m, M_DONTWAIT);
996            space = M_TRAILINGSPACE(m) - (codelen + extra);
997            if (space < 0) {
998                /* now that's what I call *compression*. */
999                m_freem(mret);
1000                return DECOMP_ERROR;
1001            }
1002            dmp = m;
1003            wptr = mtod(dmp, u_char *);
1004        }
1005
1006        /*
1007         * Decode this code and install it in the decompressed buffer.
1008         */
1009        p = (wptr += codelen);
1010        while (finchar > LAST) {
1011            dictp = &db->dict[db->dict[finchar].cptr];
1012#ifdef DEBUG
1013            if (--codelen <= 0 || dictp->codem1 != finchar-1)
1014                goto bad;
1015#endif
1016            *--p = dictp->f.hs.suffix;
1017            finchar = dictp->f.hs.prefix;
1018        }
1019        *--p = finchar;
1020
1021#ifdef DEBUG
1022        if (--codelen != 0)
1023            printf("bsd_decomp%d: short by %d after code 0x%x, max_ent=0x%x\n",
1024                   db->unit, codelen, incode, max_ent);
1025#endif
1026
1027        if (extra)              /* the KwKwK case again */
1028            *wptr++ = finchar;
1029
1030        /*
1031         * If not first code in a packet, and
1032         * if not out of code space, then allocate a new code.
1033         *
1034         * Keep the hash table correct so it can be used
1035         * with uncompressed packets.
1036         */
1037        if (oldcode != CLEAR && max_ent < db->maxmaxcode) {
1038            struct bsd_dict *dictp2;
1039            u_int32_t fcode;
1040            u_int32_t hval, disp;
1041
1042            fcode = BSD_KEY(oldcode,finchar);
1043            hval = BSD_HASH(oldcode,finchar,db->hshift);
1044            dictp = &db->dict[hval];
1045
1046            /* look for a free hash table entry */
1047            if (dictp->codem1 < max_ent) {
1048                disp = (hval == 0) ? 1 : hval;
1049                do {
1050                    hval += disp;
1051                    if (hval >= db->hsize)
1052                        hval -= db->hsize;
1053                    dictp = &db->dict[hval];
1054                } while (dictp->codem1 < max_ent);
1055            }
1056
1057            /*
1058             * Invalidate previous hash table entry
1059             * assigned this code, and then take it over
1060             */
1061            dictp2 = &db->dict[max_ent+1];
1062            if (db->dict[dictp2->cptr].codem1 == max_ent) {
1063                db->dict[dictp2->cptr].codem1 = BADCODEM1;
1064            }
1065            dictp2->cptr = hval;
1066            dictp->codem1 = max_ent;
1067            dictp->f.fcode = fcode;
1068
1069            db->max_ent = ++max_ent;
1070            db->lens[max_ent] = db->lens[oldcode]+1;
1071
1072            /* Expand code size if needed. */
1073            if (max_ent >= MAXCODE(n_bits) && max_ent < db->maxmaxcode) {
1074                db->n_bits = ++n_bits;
1075                tgtbitno = 32-n_bits;
1076            }
1077        }
1078        oldcode = incode;
1079    }
1080    dmp->m_len = wptr - mtod(dmp, u_char *);
1081
1082    /*
1083     * Keep the checkpoint right so that incompressible packets
1084     * clear the dictionary at the right times.
1085     */
1086    db->bytes_out += ilen;
1087    db->in_count += explen;
1088    if (bsd_check(db) && db->debug) {
1089        printf("bsd_decomp%d: peer should have cleared dictionary\n",
1090               db->unit);
1091    }
1092
1093    ++db->comp_count;
1094    db->comp_bytes += ilen + BSD_OVHD;
1095    ++db->uncomp_count;
1096    db->uncomp_bytes += explen;
1097
1098    *dmpp = mret;
1099    return DECOMP_OK;
1100
1101#ifdef DEBUG
1102 bad:
1103    if (codelen <= 0) {
1104        printf("bsd_decomp%d: fell off end of chain ", db->unit);
1105        printf("0x%x at 0x%x by 0x%x, max_ent=0x%x\n",
1106               incode, finchar, db->dict[finchar].cptr, max_ent);
1107    } else if (dictp->codem1 != finchar-1) {
1108        printf("bsd_decomp%d: bad code chain 0x%x finchar=0x%x ",
1109               db->unit, incode, finchar);
1110        printf("oldcode=0x%x cptr=0x%x codem1=0x%x\n", oldcode,
1111               db->dict[finchar].cptr, dictp->codem1);
1112    }
1113    m_freem(mret);
1114    return DECOMP_FATALERROR;
1115#endif /* DEBUG */
1116}
1117#endif /* DO_BSD_COMPRESS */
Note: See TracBrowser for help on using the repository browser.