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

Cache object: af07ed4ac626a71a313e2fdf43091dfc


[ 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.