The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/net/bsd_comp.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 6d1625ffb3862c56721a6af6e6d3fd11


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.