OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [net/] [ppp/] [current/] [src/] [bsd_comp.c] - Blame information for rev 786

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.