]> git.ozlabs.org Git - ppp.git/blob - ultrix/bsd-comp.c
Initial revision
[ppp.git] / ultrix / bsd-comp.c
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 Ultrix systems.
42  *
43  * $Id: bsd-comp.c,v 1.1 1994/11/21 05:02:49 paulus Exp $
44  */
45
46 #include "../h/param.h"
47 #include "../h/types.h"
48 #include "../h/mbuf.h"
49 #include "../h/socket.h"
50 #include "../net/net/if.h"
51 #include "ppp_defs.h"
52 #include "if_ppp.h"
53
54 #define PACKET  struct mbuf
55 #include "ppp-comp.h"
56
57 /*
58  * PPP "BSD compress" compression
59  *  The differences between this compression and the classic BSD LZW
60  *  source are obvious from the requirement that the classic code worked
61  *  with files while this handles arbitrarily long streams that
62  *  are broken into packets.  They are:
63  *
64  *      When the code size expands, a block of junk is not emitted by
65  *          the compressor and not expected by the decompressor.
66  *
67  *      New codes are not necessarily assigned every time an old
68  *          code is output by the compressor.  This is because a packet
69  *          end forces a code to be emitted, but does not imply that a
70  *          new sequence has been seen.
71  *
72  *      The compression ratio is checked at the first end of a packet
73  *          after the appropriate gap.  Besides simplifying and speeding
74  *          things up, this makes it more likely that the transmitter
75  *          and receiver will agree when the dictionary is cleared when
76  *          compression is not going well.
77  */
78
79 /*
80  * Macros to extract protocol version and number of bits
81  * from the third byte of the BSD Compress CCP configuration option.
82  */
83 #define BSD_VERSION(x)  ((x) >> 5)
84 #define BSD_NBITS(x)    ((x) & 0x1F)
85
86 #define BSD_CURRENT_VERSION     1
87
88 /*
89  * A dictionary for doing BSD compress.
90  */
91 struct bsd_db {
92     int     totlen;                     /* length of this structure */
93     u_int   hsize;                      /* size of the hash table */
94     u_char  hshift;                     /* used in hash function */
95     u_char  n_bits;                     /* current bits/code */
96     u_char  maxbits;
97     u_char  debug;
98     u_char  unit;
99     u_short seqno;                      /* sequence # of next packet */
100     u_int   mru;
101     u_int   maxmaxcode;                 /* largest valid code */
102     u_int   max_ent;                    /* largest code in use */
103     u_int   in_count;                   /* uncompressed bytes, aged */
104     u_int   bytes_out;                  /* compressed bytes, aged */
105     u_int   ratio;                      /* recent compression ratio */
106     u_int   checkpoint;                 /* when to next check the ratio */
107     u_int   clear_count;                /* times dictionary cleared */
108     u_int   incomp_count;               /* incompressible packets */
109     u_int   incomp_bytes;               /* incompressible bytes */
110     u_int   uncomp_count;               /* uncompressed packets */
111     u_int   uncomp_bytes;               /* uncompressed bytes */
112     u_int   comp_count;                 /* compressed packets */
113     u_int   comp_bytes;                 /* compressed bytes */
114     u_short *lens;                      /* array of lengths of codes */
115     struct bsd_dict {
116         union {                         /* hash value */
117             u_int32_t   fcode;
118             struct {
119 #if BYTE_ORDER == LITTLE_ENDIAN
120                 u_short prefix;         /* preceding code */
121                 u_char  suffix;         /* last character of new code */
122                 u_char  pad;
123 #else
124                 u_char  pad;
125                 u_char  suffix;         /* last character of new code */
126                 u_short prefix;         /* preceding code */
127 #endif
128             } hs;
129         } f;
130         u_short codem1;                 /* output of hash table -1 */
131         u_short cptr;                   /* map code to hash table entry */
132     } dict[1];
133 };
134
135 #define BSD_OVHD        2               /* BSD compress overhead/packet */
136 #define MIN_BSD_BITS    9
137 #define BSD_INIT_BITS   MIN_BSD_BITS
138 #define MAX_BSD_BITS    15
139
140 static void     *bsd_comp_alloc __P((u_char *options, int opt_len));
141 static void     *bsd_decomp_alloc __P((u_char *options, int opt_len));
142 static void     bsd_free __P((void *state));
143 static int      bsd_comp_init __P((void *state, u_char *options, int opt_len,
144                                    int unit, int debug));
145 static int      bsd_decomp_init __P((void *state, u_char *options, int opt_len,
146                                      int unit, int mru, int debug));
147 static int      bsd_compress __P((void *state, struct mbuf **mret,
148                                   struct mbuf *mp, int slen, int maxolen));
149 static void     bsd_incomp __P((void *state, struct mbuf *dmsg));
150 static int      bsd_decompress __P((void *state, struct mbuf *cmp,
151                                     struct mbuf **dmpp));
152 static void     bsd_reset __P((void *state));
153 static void     bsd_comp_stats __P((void *state, struct compstat *stats));
154
155 /*
156  * Procedures exported to if_ppp.c.
157  */
158 struct compressor ppp_bsd_compress = {
159     0x21,                       /* compress_proto */
160     bsd_comp_alloc,             /* comp_alloc */
161     bsd_free,                   /* comp_free */
162     bsd_comp_init,              /* comp_init */
163     bsd_reset,                  /* comp_reset */
164     bsd_compress,               /* compress */
165     bsd_comp_stats,             /* comp_stat */
166     bsd_decomp_alloc,           /* decomp_alloc */
167     bsd_free,                   /* decomp_free */
168     bsd_decomp_init,            /* decomp_init */
169     bsd_reset,                  /* decomp_reset */
170     bsd_decompress,             /* decompress */
171     bsd_incomp,                 /* incomp */
172     bsd_comp_stats,             /* decomp_stat */
173 };
174
175 /*
176  * Some useful mbuf macros not in mbuf.h.
177  */
178 #define M_IS_CLUSTER(m) ((m)->m_off > MMAXOFF)
179
180 #define M_TRAILINGSPACE(m) \
181         ((M_IS_CLUSTER(m) ? (u_int)(m)->m_clptr + M_CLUSTERSZ : MSIZE) \
182          - ((m)->m_off + (m)->m_len))
183
184 /*
185  * the next two codes should not be changed lightly, as they must not
186  * lie within the contiguous general code space.
187  */
188 #define CLEAR   256                     /* table clear output code */
189 #define FIRST   257                     /* first free entry */
190 #define LAST    255
191
192 #define MAXCODE(b)      ((1 << (b)) - 1)
193 #define BADCODEM1       MAXCODE(MAX_BSD_BITS);
194
195 #define BSD_HASH(prefix,suffix,hshift)  ((((u_int32_t)(suffix)) << (hshift)) \
196                                          ^ (u_int32_t)(prefix))
197 #define BSD_KEY(prefix,suffix)          ((((u_int32_t)(suffix)) << 16) \
198                                          + (u_int32_t)(prefix))
199
200 #define CHECK_GAP       10000           /* Ratio check interval */
201
202 #define RATIO_SCALE_LOG 8
203 #define RATIO_SCALE     (1<<RATIO_SCALE_LOG)
204 #define RATIO_MAX       (0x7fffffff>>RATIO_SCALE_LOG)
205
206 /*
207  * clear the dictionary
208  */
209 static void
210 bsd_clear(struct bsd_db *db)
211 {
212     db->clear_count++;
213     db->max_ent = FIRST-1;
214     db->n_bits = BSD_INIT_BITS;
215     db->ratio = 0;
216     db->bytes_out = 0;
217     db->in_count = 0;
218     db->incomp_count = 0;
219     db->checkpoint = CHECK_GAP;
220 }
221
222 /*
223  * If the dictionary is full, then see if it is time to reset it.
224  *
225  * Compute the compression ratio using fixed-point arithmetic
226  * with 8 fractional bits.
227  *
228  * Since we have an infinite stream instead of a single file,
229  * watch only the local compression ratio.
230  *
231  * Since both peers must reset the dictionary at the same time even in
232  * the absence of CLEAR codes (while packets are incompressible), they
233  * must compute the same ratio.
234  */
235 static int                              /* 1=output CLEAR */
236 bsd_check(struct bsd_db *db)
237 {
238     u_int new_ratio;
239
240     if (db->in_count >= db->checkpoint) {
241         /* age the ratio by limiting the size of the counts */
242         if (db->in_count >= RATIO_MAX
243             || db->bytes_out >= RATIO_MAX) {
244             db->in_count -= db->in_count/4;
245             db->bytes_out -= db->bytes_out/4;
246         }
247
248         db->checkpoint = db->in_count + CHECK_GAP;
249
250         if (db->max_ent >= db->maxmaxcode) {
251             /* Reset the dictionary only if the ratio is worse,
252              * or if it looks as if it has been poisoned
253              * by incompressible data.
254              *
255              * This does not overflow, because
256              *  db->in_count <= RATIO_MAX.
257              */
258             new_ratio = db->in_count << RATIO_SCALE_LOG;
259             if (db->bytes_out != 0)
260                 new_ratio /= db->bytes_out;
261
262             if (new_ratio < db->ratio || new_ratio < 1 * RATIO_SCALE) {
263                 bsd_clear(db);
264                 return 1;
265             }
266             db->ratio = new_ratio;
267         }
268     }
269     return 0;
270 }
271
272 /*
273  * Return statistics.
274  */
275 static void
276 bsd_comp_stats(state, stats)
277     void *state;
278     struct compstat *stats;
279 {
280     struct bsd_db *db = (struct bsd_db *) state;
281
282     stats->unc_bytes = db->uncomp_bytes;
283     stats->unc_packets = db->uncomp_count;
284     stats->comp_bytes = db->comp_bytes;
285     stats->comp_packets = db->comp_count;
286     stats->inc_bytes = db->incomp_bytes;
287     stats->inc_packets = db->incomp_count;
288     stats->ratio = (double) db->in_count;
289     if (db->bytes_out != 0)
290         stats->ratio /= db->bytes_out;
291 }
292
293 /*
294  * Reset state, as on a CCP ResetReq.
295  */
296 static void
297 bsd_reset(state)
298     void *state;
299 {
300     struct bsd_db *db = (struct bsd_db *) state;
301
302     db->seqno = 0;
303     bsd_clear(db);
304     db->clear_count = 0;
305 }
306
307 /*
308  * Allocate space for a (de) compressor.
309  */
310 static void *
311 bsd_alloc(options, opt_len, decomp)
312     u_char *options;
313     int opt_len, decomp;
314 {
315     int bits;
316     u_int newlen, hsize, hshift, maxmaxcode;
317     struct bsd_db *db;
318
319     if (opt_len != 3 || options[0] != 0x21 || options[1] != 3
320         || BSD_VERSION(options[2]) != BSD_CURRENT_VERSION)
321         return NULL;
322     bits = BSD_NBITS(options[2]);
323     switch (bits) {
324     case 9:                     /* needs 82152 for both directions */
325     case 10:                    /* needs 84144 */
326     case 11:                    /* needs 88240 */
327     case 12:                    /* needs 96432 */
328         hsize = 5003;
329         hshift = 4;
330         break;
331     case 13:                    /* needs 176784 */
332         hsize = 9001;
333         hshift = 5;
334         break;
335     case 14:                    /* needs 353744 */
336         hsize = 18013;
337         hshift = 6;
338         break;
339     case 15:                    /* needs 691440 */
340         hsize = 35023;
341         hshift = 7;
342         break;
343     case 16:                    /* needs 1366160--far too much, */
344         /* hsize = 69001; */    /* and 69001 is too big for cptr */
345         /* hshift = 8; */       /* in struct bsd_db */
346         /* break; */
347     default:
348         return NULL;
349     }
350
351     maxmaxcode = MAXCODE(bits);
352     newlen = sizeof(*db) + (hsize-1)*(sizeof(db->dict[0]));
353     MALLOC(db, struct bsd_db *, newlen, M_DEVBUF, M_NOWAIT);
354     if (!db)
355         return NULL;
356     bzero(db, sizeof(*db) - sizeof(db->dict));
357
358     if (!decomp) {
359         db->lens = NULL;
360     } else {
361         MALLOC(db->lens, u_short *, (maxmaxcode+1) * sizeof(db->lens[0]),
362                M_DEVBUF, M_NOWAIT);
363         if (!db->lens) {
364             FREE(db, M_DEVBUF);
365             return NULL;
366         }
367     }
368
369     db->totlen = newlen;
370     db->hsize = hsize;
371     db->hshift = hshift;
372     db->maxmaxcode = maxmaxcode;
373     db->maxbits = bits;
374
375     return (void *) db;
376 }
377
378 static void
379 bsd_free(state)
380     void *state;
381 {
382     struct bsd_db *db = (struct bsd_db *) state;
383
384     if (db->lens)
385         FREE(db->lens, M_DEVBUF);
386     FREE(db, M_DEVBUF);
387 }
388
389 static void *
390 bsd_comp_alloc(options, opt_len)
391     u_char *options;
392     int opt_len;
393 {
394     return bsd_alloc(options, opt_len, 0);
395 }
396
397 static void *
398 bsd_decomp_alloc(options, opt_len)
399     u_char *options;
400     int opt_len;
401 {
402     return bsd_alloc(options, opt_len, 1);
403 }
404
405 /*
406  * Initialize the database.
407  */
408 static int
409 bsd_init(db, options, opt_len, unit, mru, debug, decomp)
410     struct bsd_db *db;
411     u_char *options;
412     int opt_len, unit, mru, debug, decomp;
413 {
414     int i;
415
416     if (opt_len != 3 || options[0] != 0x21 || options[1] != 3
417         || BSD_VERSION(options[2]) != BSD_CURRENT_VERSION
418         || BSD_NBITS(options[2]) != db->maxbits
419         || decomp && db->lens == NULL)
420         return 0;
421
422     if (decomp) {
423         i = LAST+1;
424         while (i != 0)
425             db->lens[--i] = 1;
426     }
427     i = db->hsize;
428     while (i != 0) {
429         db->dict[--i].codem1 = BADCODEM1;
430         db->dict[i].cptr = 0;
431     }
432
433     db->unit = unit;
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
445 static int
446 bsd_comp_init(state, options, opt_len, unit, debug)
447     void *state;
448     u_char *options;
449     int opt_len, unit, debug;
450 {
451     return bsd_init((struct bsd_db *) state, options, opt_len,
452                     unit, 0, debug, 0);
453 }
454
455 static int
456 bsd_decomp_init(state, options, opt_len, unit, mru, debug)
457     void *state;
458     u_char *options;
459     int opt_len, unit, mru, debug;
460 {
461     return bsd_init((struct bsd_db *) state, options, opt_len,
462                     unit, 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  */
471 int                                     /* new slen */
472 bsd_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     struct mbuf *np;
489     u_char *rptr, *wptr;
490     u_char *cp_end;
491     int olen;
492     struct mbuf *m, **mnp, *clp;
493         
494 #define PUTBYTE(v) {                                    \
495     ++olen;                                             \
496     if (wptr) {                                         \
497         *wptr++ = (v);                                  \
498         if (wptr >= cp_end) {                           \
499             m->m_len = wptr - mtod(m, u_char *);        \
500             MGET(m->m_next, M_DONTWAIT, MT_DATA);       \
501             m = m->m_next;                              \
502             if (m) {                                    \
503                 m->m_len = 0;                           \
504                 if (maxolen - olen > MLEN)              \
505                     MCLGET(m, clp);                     \
506                 wptr = mtod(m, u_char *);               \
507                 cp_end = wptr + M_TRAILINGSPACE(m);     \
508             } else                                      \
509                 wptr = NULL;                            \
510         }                                               \
511     }                                                   \
512 }
513
514 #define OUTPUT(ent) {                                   \
515     bitno -= n_bits;                                    \
516     accm |= ((ent) << bitno);                           \
517     do {                                                \
518         PUTBYTE(accm >> 24);                            \
519         accm <<= 8;                                     \
520         bitno += 8;                                     \
521     } while (bitno <= 24);                              \
522 }
523
524     /*
525      * If the protocol is not in the range we're interested in,
526      * just return without compressing the packet.  If it is,
527      * the protocol becomes the first byte to compress.
528      */
529     rptr = mtod(mp, u_char *);
530     ent = PPP_PROTOCOL(rptr);
531     if (ent < 0x21 || ent > 0xf9) {
532         *mret = NULL;
533         return slen;
534     }
535
536     /* Don't generate compressed packets which are larger than
537        the uncompressed packet. */
538     if (maxolen > slen)
539         maxolen = slen;
540
541     /* Allocate one mbuf to start with. */
542     MGET(m, M_DONTWAIT, MT_DATA);
543     *mret = m;
544     if (m != NULL) {
545         m->m_len = 0;
546         if (maxolen > MLEN)
547             MCLGET(m, clp);
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 && *mret != NULL) {
666         /* throw away the compressed stuff if it is longer than uncompressed */
667         m_freem(*mret);
668         *mret = NULL;
669         ++db->incomp_count;
670         db->incomp_bytes += ilen;
671     } else {
672         ++db->comp_count;
673         db->comp_bytes += olen + BSD_OVHD;
674     }
675
676     return olen + PPP_HDRLEN + BSD_OVHD;
677 #undef OUTPUT
678 #undef PUTBYTE
679 }
680
681
682 /*
683  * Update the "BSD Compress" dictionary on the receiver for
684  * incompressible data by pretending to compress the incoming data.
685  */
686 static void
687 bsd_incomp(state, dmsg)
688     void *state;
689     struct mbuf *dmsg;
690 {
691     struct bsd_db *db = (struct bsd_db *) state;
692     u_int hshift = db->hshift;
693     u_int max_ent = db->max_ent;
694     u_int n_bits = db->n_bits;
695     struct bsd_dict *dictp;
696     u_int32_t fcode;
697     u_char c;
698     long hval, disp;
699     int slen, ilen;
700     u_int bitno = 7;
701     u_char *rptr;
702     u_int ent;
703
704     /*
705      * If the protocol is not in the range we're interested in,
706      * just return without looking at the packet.  If it is,
707      * the protocol becomes the first byte to "compress".
708      */
709     rptr = mtod(dmsg, u_char *);
710     ent = PPP_PROTOCOL(rptr);
711     if (ent < 0x21 || ent > 0xf9)
712         return;
713
714     db->incomp_count++;
715     db->seqno++;
716     ilen = 1;           /* count the protocol as 1 byte */
717     rptr += PPP_HDRLEN;
718     slen = dmsg->m_len - PPP_HDRLEN;
719     for (;;) {
720         if (slen <= 0) {
721             dmsg = dmsg->m_next;
722             if (!dmsg)
723                 break;
724             rptr = mtod(dmsg, u_char *);
725             slen = dmsg->m_len;
726             continue;
727         }
728         ilen += slen;
729
730         do {
731             c = *rptr++;
732             fcode = BSD_KEY(ent, c);
733             hval = BSD_HASH(ent, c, hshift);
734             dictp = &db->dict[hval];
735
736             /* validate and then check the entry */
737             if (dictp->codem1 >= max_ent)
738                 goto nomatch;
739             if (dictp->f.fcode == fcode) {
740                 ent = dictp->codem1+1;
741                 continue;   /* found (prefix,suffix) */
742             }
743
744             /* continue probing until a match or invalid entry */
745             disp = (hval == 0) ? 1 : hval;
746             do {
747                 hval += disp;
748                 if (hval >= db->hsize)
749                     hval -= db->hsize;
750                 dictp = &db->dict[hval];
751                 if (dictp->codem1 >= max_ent)
752                     goto nomatch;
753             } while (dictp->f.fcode != fcode);
754             ent = dictp->codem1+1;
755             continue;   /* finally found (prefix,suffix) */
756
757         nomatch:                /* output (count) the prefix */
758             bitno += n_bits;
759
760             /* code -> hashtable */
761             if (max_ent < db->maxmaxcode) {
762                 struct bsd_dict *dictp2;
763                 /* expand code size if needed */
764                 if (max_ent >= MAXCODE(n_bits))
765                     db->n_bits = ++n_bits;
766
767                 /* Invalidate previous hash table entry
768                  * assigned this code, and then take it over.
769                  */
770                 dictp2 = &db->dict[max_ent+1];
771                 if (db->dict[dictp2->cptr].codem1 == max_ent)
772                     db->dict[dictp2->cptr].codem1 = BADCODEM1;
773                 dictp2->cptr = hval;
774                 dictp->codem1 = max_ent;
775                 dictp->f.fcode = fcode;
776
777                 db->max_ent = ++max_ent;
778                 db->lens[max_ent] = db->lens[ent]+1;
779             }
780             ent = c;
781         } while (--slen != 0);
782     }
783     bitno += n_bits;            /* output (count) the last code */
784     db->bytes_out += bitno/8;
785     db->in_count += ilen;
786     (void)bsd_check(db);
787
788     ++db->comp_count;
789     db->comp_bytes += bitno / 8;
790     ++db->incomp_count;
791     db->incomp_bytes += ilen;
792
793     /* Increase code size if we would have without the packet
794      * boundary and as the decompressor will.
795      */
796     if (max_ent >= MAXCODE(n_bits) && max_ent < db->maxmaxcode)
797         db->n_bits++;
798 }
799
800
801 /*
802  * Decompress "BSD Compress"
803  */
804 int
805 bsd_decompress(state, cmp, dmpp)
806     void *state;
807     struct mbuf *cmp, **dmpp;
808 {
809     struct bsd_db *db = (struct bsd_db *) state;
810     u_int max_ent = db->max_ent;
811     u_int32_t accm = 0;
812     u_int bitno = 32;           /* 1st valid bit in accm */
813     u_int n_bits = db->n_bits;
814     u_int tgtbitno = 32-n_bits; /* bitno when we have a code */
815     struct bsd_dict *dictp;
816     int explen, i, seq, len;
817     u_int incode, oldcode, finchar;
818     u_char *p, *rptr, *wptr;
819     struct mbuf *m, *dmp, *mret;
820     int adrs, ctrl, ilen;
821     int space, codelen, extra;
822     struct mbuf *last, *clp;
823
824     /*
825      * Save the address/control from the PPP header
826      * and then get the sequence number.
827      */
828     *dmpp = NULL;
829     rptr = mtod(cmp, u_char *);
830     adrs = PPP_ADDRESS(rptr);
831     ctrl = PPP_CONTROL(rptr);
832     rptr += PPP_HDRLEN;
833     len = cmp->m_len - PPP_HDRLEN;
834     seq = 0;
835     for (i = 0; i < 2; ++i) {
836         while (len <= 0) {
837             cmp = cmp->m_next;
838             if (cmp == NULL)
839                 return DECOMP_ERROR;
840             rptr = mtod(cmp, u_char *);
841             len = cmp->m_len;
842         }
843         seq = (seq << 8) + *rptr++;
844         --len;
845     }
846
847     /*
848      * Check the sequence number and give up if it differs from
849      * the value we're expecting.
850      */
851     if (seq != db->seqno++) {
852         if (db->debug)
853             printf("bsd_decomp%d: bad sequence # %d, expected %d\n",
854                    db->unit, seq, db->seqno - 1);
855         return DECOMP_ERROR;
856     }
857
858     /*
859      * Allocate one mbuf to start with.
860      */
861     MGET(dmp, M_DONTWAIT, MT_DATA);
862     if (dmp == NULL)
863         return DECOMP_ERROR;
864     mret = dmp;
865     dmp->m_len = 0;
866     dmp->m_next = NULL;
867     MCLGET(dmp, clp);
868     wptr = mtod(dmp, u_char *);
869     space = M_TRAILINGSPACE(dmp) - PPP_HDRLEN + 1;
870
871     /*
872      * Fill in the ppp header, but not the last byte of the protocol
873      * (that comes from the decompressed data).
874      */
875     wptr[0] = adrs;
876     wptr[1] = ctrl;
877     wptr[2] = 0;
878     wptr += PPP_HDRLEN - 1;
879
880     ilen = len;
881     oldcode = CLEAR;
882     explen = 0;
883     for (;;) {
884         if (len == 0) {
885             cmp = cmp->m_next;
886             if (!cmp)           /* quit at end of message */
887                 break;
888             rptr = mtod(cmp, u_char *);
889             len = cmp->m_len;
890             ilen += len;
891             continue;           /* handle 0-length buffers */
892         }
893
894         /*
895          * Accumulate bytes until we have a complete code.
896          * Then get the next code, relying on the 32-bit,
897          * unsigned accm to mask the result.
898          */
899         bitno -= 8;
900         accm |= *rptr++ << bitno;
901         --len;
902         if (tgtbitno < bitno)
903             continue;
904         incode = accm >> tgtbitno;
905         accm <<= n_bits;
906         bitno += n_bits;
907
908         if (incode == CLEAR) {
909             /*
910              * The dictionary must only be cleared at
911              * the end of a packet.  But there could be an
912              * empty mbuf at the end.
913              */
914             if (len > 0 || cmp->m_next != NULL) {
915                 while ((cmp = cmp->m_next) != NULL)
916                     len += cmp->m_len;
917                 if (len > 0) {
918                     m_freem(mret);
919                     if (db->debug)
920                         printf("bsd_decomp%d: bad CLEAR\n", db->unit);
921                     return DECOMP_FATALERROR;   /* probably a bug */
922                 }
923             }
924             bsd_clear(db);
925             explen = 0;
926             break;
927         }
928
929         if (incode > max_ent + 2 || incode > db->maxmaxcode
930             || incode > max_ent && oldcode == CLEAR) {
931             m_freem(mret);
932             if (db->debug) {
933                 printf("bsd_decomp%d: bad code 0x%x oldcode=0x%x ",
934                        db->unit, incode, oldcode);
935                 printf("max_ent=0x%x explen=%d seqno=%d\n",
936                        max_ent, explen, db->seqno);
937             }
938             return DECOMP_FATALERROR;   /* probably a bug */
939         }
940
941         /* Special case for KwKwK string. */
942         if (incode > max_ent) {
943             finchar = oldcode;
944             extra = 1;
945         } else {
946             finchar = incode;
947             extra = 0;
948         }
949
950         codelen = db->lens[finchar];
951         explen += codelen + extra;
952         if (explen > db->mru + 1) {
953             m_freem(mret);
954             if (db->debug) {
955                 printf("bsd_decomp%d: ran out of mru\n", db->unit);
956 #ifdef DEBUG
957                 while ((cmp = cmp->m_next) != NULL)
958                     len += cmp->m_len;
959                 printf("  len=%d, finchar=0x%x, codelen=%d, explen=%d\n",
960                        len, finchar, codelen, explen);
961 #endif
962             }
963             return DECOMP_FATALERROR;
964         }
965
966         /*
967          * For simplicity, the decoded characters go in a single mbuf,
968          * so we allocate a single extra cluster mbuf if necessary.
969          */
970         if ((space -= codelen + extra) < 0) {
971             dmp->m_len = wptr - mtod(dmp, u_char *);
972             MGET(m, M_DONTWAIT, MT_DATA);
973             if (m == NULL) {
974                 m_freem(mret);
975                 return DECOMP_ERROR;
976             }
977             m->m_len = 0;
978             m->m_next = NULL;
979             dmp->m_next = m;
980             MCLGET(m, clp);
981             space = M_TRAILINGSPACE(m) - (codelen + extra);
982             if (space < 0) {
983                 /* now that's what I call *compression*. */
984                 m_freem(mret);
985                 return DECOMP_ERROR;
986             }
987             dmp = m;
988             wptr = mtod(dmp, u_char *);
989         }
990
991         /*
992          * Decode this code and install it in the decompressed buffer.
993          */
994         p = (wptr += codelen);
995         while (finchar > LAST) {
996             dictp = &db->dict[db->dict[finchar].cptr];
997 #ifdef DEBUG
998             if (--codelen <= 0 || dictp->codem1 != finchar-1)
999                 goto bad;
1000 #endif
1001             *--p = dictp->f.hs.suffix;
1002             finchar = dictp->f.hs.prefix;
1003         }
1004         *--p = finchar;
1005
1006 #ifdef DEBUG
1007         if (--codelen != 0)
1008             printf("bsd_decomp%d: short by %d after code 0x%x, max_ent=0x%x\n",
1009                    db->unit, codelen, incode, max_ent);
1010 #endif
1011
1012         if (extra)              /* the KwKwK case again */
1013             *wptr++ = finchar;
1014
1015         /*
1016          * If not first code in a packet, and
1017          * if not out of code space, then allocate a new code.
1018          *
1019          * Keep the hash table correct so it can be used
1020          * with uncompressed packets.
1021          */
1022         if (oldcode != CLEAR && max_ent < db->maxmaxcode) {
1023             struct bsd_dict *dictp2;
1024             u_int32_t fcode;
1025             int hval, disp;
1026
1027             fcode = BSD_KEY(oldcode,finchar);
1028             hval = BSD_HASH(oldcode,finchar,db->hshift);
1029             dictp = &db->dict[hval];
1030
1031             /* look for a free hash table entry */
1032             if (dictp->codem1 < max_ent) {
1033                 disp = (hval == 0) ? 1 : hval;
1034                 do {
1035                     hval += disp;
1036                     if (hval >= db->hsize)
1037                         hval -= db->hsize;
1038                     dictp = &db->dict[hval];
1039                 } while (dictp->codem1 < max_ent);
1040             }
1041
1042             /*
1043              * Invalidate previous hash table entry
1044              * assigned this code, and then take it over
1045              */
1046             dictp2 = &db->dict[max_ent+1];
1047             if (db->dict[dictp2->cptr].codem1 == max_ent) {
1048                 db->dict[dictp2->cptr].codem1 = BADCODEM1;
1049             }
1050             dictp2->cptr = hval;
1051             dictp->codem1 = max_ent;
1052             dictp->f.fcode = fcode;
1053
1054             db->max_ent = ++max_ent;
1055             db->lens[max_ent] = db->lens[oldcode]+1;
1056
1057             /* Expand code size if needed. */
1058             if (max_ent >= MAXCODE(n_bits) && max_ent < db->maxmaxcode) {
1059                 db->n_bits = ++n_bits;
1060                 tgtbitno = 32-n_bits;
1061             }
1062         }
1063         oldcode = incode;
1064     }
1065     dmp->m_len = wptr - mtod(dmp, u_char *);
1066
1067     /*
1068      * Keep the checkpoint right so that incompressible packets
1069      * clear the dictionary at the right times.
1070      */
1071     db->bytes_out += ilen;
1072     db->in_count += explen;
1073     if (bsd_check(db) && db->debug) {
1074         printf("bsd_decomp%d: peer should have cleared dictionary\n",
1075                db->unit);
1076     }
1077
1078     ++db->comp_count;
1079     db->comp_bytes += ilen + BSD_OVHD;
1080     ++db->uncomp_count;
1081     db->uncomp_bytes += explen;
1082
1083     *dmpp = mret;
1084     return DECOMP_OK;
1085
1086 #ifdef DEBUG
1087  bad:
1088     if (codelen <= 0) {
1089         printf("bsd_decomp%d: fell off end of chain ", db->unit);
1090         printf("0x%x at 0x%x by 0x%x, max_ent=0x%x\n",
1091                incode, finchar, db->dict[finchar].cptr, max_ent);
1092     } else if (dictp->codem1 != finchar-1) {
1093         printf("bsd_decomp%d: bad code chain 0x%x finchar=0x%x ",
1094                db->unit, incode, finchar);
1095         printf("oldcode=0x%x cptr=0x%x codem1=0x%x\n", oldcode,
1096                db->dict[finchar].cptr, dictp->codem1);
1097     }
1098     m_freem(mret);
1099     return DECOMP_FATALERROR;
1100 #endif /* DEBUG */
1101 }