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