source: rtems/cpukit/pppd/ccp.c @ df49c60

4.104.114.84.9
Last change on this file since df49c60 was d0950ad, checked in by Joel Sherrill <joel.sherrill@…>, on Nov 30, 1999 at 10:12:50 PM

Added port of ppp-2.3.5 from Tomasz Domin <dot@…> of ComArch? SA.
Tomasz only tested this on the mpc823.

The official site for the original source for this PPP implementation is:

ftp://cs.anu.edu.au/pub/software/ppp

NOTE: As of 11/30/1999, the current version of this source is 2.3.10.

  • Property mode set to 100644
File size: 26.9 KB
Line 
1/*
2 * ccp.c - PPP Compression Control Protocol.
3 *
4 * Copyright (c) 1994 The Australian National University.
5 * All rights reserved.
6 *
7 * Permission to use, copy, modify, and distribute this software and its
8 * documentation is hereby granted, provided that the above copyright
9 * notice appears in all copies.  This software is provided without any
10 * warranty, express or implied. The Australian National University
11 * makes no representations about the suitability of this software for
12 * any purpose.
13 *
14 * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
15 * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
16 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
17 * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
18 * OF SUCH DAMAGE.
19 *
20 * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
21 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
22 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
23 * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
24 * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
25 * OR MODIFICATIONS.
26 */
27
28#ifndef lint
29/* static char rcsid[] = "$Id$"; */
30#endif
31
32#include <string.h>
33#include <syslog.h>
34#include <sys/ioctl.h>
35#include <sys/types.h>
36
37#include "pppd.h"
38#include "fsm.h"
39#include "ccp.h"
40#include <net/ppp-comp.h>
41
42/*
43 * Protocol entry points from main code.
44 */
45static void ccp_init __P((int unit));
46static void ccp_open __P((int unit));
47static void ccp_close __P((int unit, char *));
48static void ccp_lowerup __P((int unit));
49static void ccp_lowerdown __P((int));
50static void ccp_input __P((int unit, u_char *pkt, int len));
51static void ccp_protrej __P((int unit));
52static int  ccp_printpkt __P((u_char *pkt, int len,
53                              void (*printer) __P((void *, char *, ...)),
54                              void *arg));
55static void ccp_datainput __P((int unit, u_char *pkt, int len));
56
57struct protent ccp_protent = {
58    PPP_CCP,
59    ccp_init,
60    ccp_input,
61    ccp_protrej,
62    ccp_lowerup,
63    ccp_lowerdown,
64    ccp_open,
65    ccp_close,
66    ccp_printpkt,
67    ccp_datainput,
68    1,
69    "CCP",
70    NULL,
71    NULL,
72    NULL
73};
74
75fsm ccp_fsm[NUM_PPP];
76ccp_options ccp_wantoptions[NUM_PPP];   /* what to request the peer to use */
77ccp_options ccp_gotoptions[NUM_PPP];    /* what the peer agreed to do */
78ccp_options ccp_allowoptions[NUM_PPP];  /* what we'll agree to do */
79ccp_options ccp_hisoptions[NUM_PPP];    /* what we agreed to do */
80
81/*
82 * Callbacks for fsm code.
83 */
84static void ccp_resetci __P((fsm *));
85static int  ccp_cilen __P((fsm *));
86static void ccp_addci __P((fsm *, u_char *, int *));
87static int  ccp_ackci __P((fsm *, u_char *, int));
88static int  ccp_nakci __P((fsm *, u_char *, int));
89static int  ccp_rejci __P((fsm *, u_char *, int));
90static int  ccp_reqci __P((fsm *, u_char *, int *, int));
91static void ccp_up __P((fsm *));
92static void ccp_down __P((fsm *));
93static int  ccp_extcode __P((fsm *, int, int, u_char *, int));
94static void ccp_rack_timeout __P((void *));
95static char *method_name __P((ccp_options *, ccp_options *));
96
97static fsm_callbacks ccp_callbacks = {
98    ccp_resetci,
99    ccp_cilen,
100    ccp_addci,
101    ccp_ackci,
102    ccp_nakci,
103    ccp_rejci,
104    ccp_reqci,
105    ccp_up,
106    ccp_down,
107    NULL,
108    NULL,
109    NULL,
110    NULL,
111    ccp_extcode,
112    "CCP"
113};
114
115/*
116 * Do we want / did we get any compression?
117 */
118#define ANY_COMPRESS(opt)       ((opt).deflate || (opt).bsd_compress \
119                                 || (opt).predictor_1 || (opt).predictor_2)
120
121/*
122 * Local state (mainly for handling reset-reqs and reset-acks).
123 */
124static int ccp_localstate[NUM_PPP];
125#define RACK_PENDING    1       /* waiting for reset-ack */
126#define RREQ_REPEAT     2       /* send another reset-req if no reset-ack */
127
128#define RACKTIMEOUT     1       /* second */
129
130static int all_rejected[NUM_PPP];       /* we rejected all peer's options */
131
132/*
133 * ccp_init - initialize CCP.
134 */
135static void
136ccp_init(unit)
137    int unit;
138{
139    fsm *f = &ccp_fsm[unit];
140
141    f->unit = unit;
142    f->protocol = PPP_CCP;
143    f->callbacks = &ccp_callbacks;
144    fsm_init(f);
145
146    memset(&ccp_wantoptions[unit],  0, sizeof(ccp_options));
147    memset(&ccp_gotoptions[unit],   0, sizeof(ccp_options));
148    memset(&ccp_allowoptions[unit], 0, sizeof(ccp_options));
149    memset(&ccp_hisoptions[unit],   0, sizeof(ccp_options));
150
151    ccp_wantoptions[0].deflate = 1;
152    ccp_wantoptions[0].deflate_size = DEFLATE_MAX_SIZE;
153    ccp_wantoptions[0].deflate_correct = 1;
154    ccp_wantoptions[0].deflate_draft = 1;
155    ccp_allowoptions[0].deflate = 1;
156    ccp_allowoptions[0].deflate_size = DEFLATE_MAX_SIZE;
157    ccp_allowoptions[0].deflate_correct = 1;
158    ccp_allowoptions[0].deflate_draft = 1;
159
160    ccp_wantoptions[0].bsd_compress = 1;
161    ccp_wantoptions[0].bsd_bits = BSD_MAX_BITS;
162    ccp_allowoptions[0].bsd_compress = 1;
163    ccp_allowoptions[0].bsd_bits = BSD_MAX_BITS;
164
165    ccp_allowoptions[0].predictor_1 = 1;
166}
167
168/*
169 * ccp_open - CCP is allowed to come up.
170 */
171static void
172ccp_open(unit)
173    int unit;
174{
175    fsm *f = &ccp_fsm[unit];
176
177    if (f->state != OPENED)
178        ccp_flags_set(unit, 1, 0);
179
180    /*
181     * Find out which compressors the kernel supports before
182     * deciding whether to open in silent mode.
183     */
184    ccp_resetci(f);
185    if (!ANY_COMPRESS(ccp_gotoptions[unit]))
186        f->flags |= OPT_SILENT;
187
188    fsm_open(f);
189}
190
191/*
192 * ccp_close - Terminate CCP.
193 */
194static void
195ccp_close(unit, reason)
196    int unit;
197    char *reason;
198{
199    ccp_flags_set(unit, 0, 0);
200    fsm_close(&ccp_fsm[unit], reason);
201}
202
203/*
204 * ccp_lowerup - we may now transmit CCP packets.
205 */
206static void
207ccp_lowerup(unit)
208    int unit;
209{
210    fsm_lowerup(&ccp_fsm[unit]);
211}
212
213/*
214 * ccp_lowerdown - we may not transmit CCP packets.
215 */
216static void
217ccp_lowerdown(unit)
218    int unit;
219{
220    fsm_lowerdown(&ccp_fsm[unit]);
221}
222
223/*
224 * ccp_input - process a received CCP packet.
225 */
226static void
227ccp_input(unit, p, len)
228    int unit;
229    u_char *p;
230    int len;
231{
232    fsm *f = &ccp_fsm[unit];
233    int oldstate;
234
235    /*
236     * Check for a terminate-request so we can print a message.
237     */
238    oldstate = f->state;
239    fsm_input(f, p, len);
240    if (oldstate == OPENED && p[0] == TERMREQ && f->state != OPENED);
241        syslog(LOG_NOTICE, "Compression disabled by peer.");
242
243    /*
244     * If we get a terminate-ack and we're not asking for compression,
245     * close CCP.
246     */
247    if (oldstate == REQSENT && p[0] == TERMACK
248        && !ANY_COMPRESS(ccp_gotoptions[unit]))
249        ccp_close(unit, "No compression negotiated");
250}
251
252/*
253 * Handle a CCP-specific code.
254 */
255static int
256ccp_extcode(f, code, id, p, len)
257    fsm *f;
258    int code, id;
259    u_char *p;
260    int len;
261{
262    switch (code) {
263    case CCP_RESETREQ:
264        if (f->state != OPENED)
265            break;
266        /* send a reset-ack, which the transmitter will see and
267           reset its compression state. */
268        fsm_sdata(f, CCP_RESETACK, id, NULL, 0);
269        break;
270
271    case CCP_RESETACK:
272        if (ccp_localstate[f->unit] & RACK_PENDING && id == f->reqid) {
273            ccp_localstate[f->unit] &= ~(RACK_PENDING | RREQ_REPEAT);
274            UNTIMEOUT(ccp_rack_timeout, f);
275        }
276        break;
277
278    default:
279        return 0;
280    }
281
282    return 1;
283}
284
285/*
286 * ccp_protrej - peer doesn't talk CCP.
287 */
288static void
289ccp_protrej(unit)
290    int unit;
291{
292    ccp_flags_set(unit, 0, 0);
293    fsm_lowerdown(&ccp_fsm[unit]);
294}
295
296/*
297 * ccp_resetci - initialize at start of negotiation.
298 */
299static void
300ccp_resetci(f)
301    fsm *f;
302{
303    ccp_options *go = &ccp_gotoptions[f->unit];
304    u_char opt_buf[16];
305
306    *go = ccp_wantoptions[f->unit];
307    all_rejected[f->unit] = 0;
308
309    /*
310     * Check whether the kernel knows about the various
311     * compression methods we might request.
312     */
313    if (go->bsd_compress) {
314        opt_buf[0] = CI_BSD_COMPRESS;
315        opt_buf[1] = CILEN_BSD_COMPRESS;
316        opt_buf[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, BSD_MIN_BITS);
317        if (ccp_test(f->unit, opt_buf, CILEN_BSD_COMPRESS, 0) <= 0)
318            go->bsd_compress = 0;
319    }
320    if (go->deflate) {
321        if (go->deflate_correct) {
322            opt_buf[0] = CI_DEFLATE;
323            opt_buf[1] = CILEN_DEFLATE;
324            opt_buf[2] = DEFLATE_MAKE_OPT(DEFLATE_MIN_SIZE);
325            opt_buf[3] = DEFLATE_CHK_SEQUENCE;
326            if (ccp_test(f->unit, opt_buf, CILEN_DEFLATE, 0) <= 0)
327                go->deflate_correct = 0;
328        }
329        if (go->deflate_draft) {
330            opt_buf[0] = CI_DEFLATE_DRAFT;
331            opt_buf[1] = CILEN_DEFLATE;
332            opt_buf[2] = DEFLATE_MAKE_OPT(DEFLATE_MIN_SIZE);
333            opt_buf[3] = DEFLATE_CHK_SEQUENCE;
334            if (ccp_test(f->unit, opt_buf, CILEN_DEFLATE, 0) <= 0)
335                go->deflate_draft = 0;
336        }
337        if (!go->deflate_correct && !go->deflate_draft)
338            go->deflate = 0;
339    }
340    if (go->predictor_1) {
341        opt_buf[0] = CI_PREDICTOR_1;
342        opt_buf[1] = CILEN_PREDICTOR_1;
343        if (ccp_test(f->unit, opt_buf, CILEN_PREDICTOR_1, 0) <= 0)
344            go->predictor_1 = 0;
345    }
346    if (go->predictor_2) {
347        opt_buf[0] = CI_PREDICTOR_2;
348        opt_buf[1] = CILEN_PREDICTOR_2;
349        if (ccp_test(f->unit, opt_buf, CILEN_PREDICTOR_2, 0) <= 0)
350            go->predictor_2 = 0;
351    }
352}
353
354/*
355 * ccp_cilen - Return total length of our configuration info.
356 */
357static int
358ccp_cilen(f)
359    fsm *f;
360{
361    ccp_options *go = &ccp_gotoptions[f->unit];
362
363    return (go->bsd_compress? CILEN_BSD_COMPRESS: 0)
364        + (go->deflate? CILEN_DEFLATE: 0)
365        + (go->predictor_1? CILEN_PREDICTOR_1: 0)
366        + (go->predictor_2? CILEN_PREDICTOR_2: 0);
367}
368
369/*
370 * ccp_addci - put our requests in a packet.
371 */
372static void
373ccp_addci(f, p, lenp)
374    fsm *f;
375    u_char *p;
376    int *lenp;
377{
378    int res;
379    ccp_options *go = &ccp_gotoptions[f->unit];
380    u_char *p0 = p;
381
382    /*
383     * Add the compression types that we can receive, in decreasing
384     * preference order.  Get the kernel to allocate the first one
385     * in case it gets Acked.
386     */
387    if (go->deflate) {
388        p[0] = go->deflate_correct? CI_DEFLATE: CI_DEFLATE_DRAFT;
389        p[1] = CILEN_DEFLATE;
390        p[2] = DEFLATE_MAKE_OPT(go->deflate_size);
391        p[3] = DEFLATE_CHK_SEQUENCE;
392        for (;;) {
393            res = ccp_test(f->unit, p, CILEN_DEFLATE, 0);
394            if (res > 0) {
395                p += CILEN_DEFLATE;
396                break;
397            }
398            if (res < 0 || go->deflate_size <= DEFLATE_MIN_SIZE) {
399                go->deflate = 0;
400                break;
401            }
402            --go->deflate_size;
403            p[2] = DEFLATE_MAKE_OPT(go->deflate_size);
404        }
405        if (p != p0 && go->deflate_correct && go->deflate_draft) {
406            p[0] = CI_DEFLATE_DRAFT;
407            p[1] = CILEN_DEFLATE;
408            p[2] = p[2 - CILEN_DEFLATE];
409            p[3] = DEFLATE_CHK_SEQUENCE;
410            p += CILEN_DEFLATE;
411        }
412    }
413    if (go->bsd_compress) {
414        p[0] = CI_BSD_COMPRESS;
415        p[1] = CILEN_BSD_COMPRESS;
416        p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits);
417        if (p != p0) {
418            p += CILEN_BSD_COMPRESS;    /* not the first option */
419        } else {
420            for (;;) {
421                res = ccp_test(f->unit, p, CILEN_BSD_COMPRESS, 0);
422                if (res > 0) {
423                    p += CILEN_BSD_COMPRESS;
424                    break;
425                }
426                if (res < 0 || go->bsd_bits <= BSD_MIN_BITS) {
427                    go->bsd_compress = 0;
428                    break;
429                }
430                --go->bsd_bits;
431                p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits);
432            }
433        }
434    }
435    /* XXX Should Predictor 2 be preferable to Predictor 1? */
436    if (go->predictor_1) {
437        p[0] = CI_PREDICTOR_1;
438        p[1] = CILEN_PREDICTOR_1;
439        if (p == p0 && ccp_test(f->unit, p, CILEN_PREDICTOR_1, 0) <= 0) {
440            go->predictor_1 = 0;
441        } else {
442            p += CILEN_PREDICTOR_1;
443        }
444    }
445    if (go->predictor_2) {
446        p[0] = CI_PREDICTOR_2;
447        p[1] = CILEN_PREDICTOR_2;
448        if (p == p0 && ccp_test(f->unit, p, CILEN_PREDICTOR_2, 0) <= 0) {
449            go->predictor_2 = 0;
450        } else {
451            p += CILEN_PREDICTOR_2;
452        }
453    }
454
455    go->method = (p > p0)? p0[0]: -1;
456
457    *lenp = p - p0;
458}
459
460/*
461 * ccp_ackci - process a received configure-ack, and return
462 * 1 iff the packet was OK.
463 */
464static int
465ccp_ackci(f, p, len)
466    fsm *f;
467    u_char *p;
468    int len;
469{
470    ccp_options *go = &ccp_gotoptions[f->unit];
471    u_char *p0 = p;
472
473    if (go->deflate) {
474        if (len < CILEN_DEFLATE
475            || p[0] != (go->deflate_correct? CI_DEFLATE: CI_DEFLATE_DRAFT)
476            || p[1] != CILEN_DEFLATE
477            || p[2] != DEFLATE_MAKE_OPT(go->deflate_size)
478            || p[3] != DEFLATE_CHK_SEQUENCE)
479            return 0;
480        p += CILEN_DEFLATE;
481        len -= CILEN_DEFLATE;
482        /* XXX Cope with first/fast ack */
483        if (len == 0)
484            return 1;
485        if (go->deflate_correct && go->deflate_draft) {
486            if (len < CILEN_DEFLATE
487                || p[0] != CI_DEFLATE_DRAFT
488                || p[1] != CILEN_DEFLATE
489                || p[2] != DEFLATE_MAKE_OPT(go->deflate_size)
490                || p[3] != DEFLATE_CHK_SEQUENCE)
491                return 0;
492            p += CILEN_DEFLATE;
493            len -= CILEN_DEFLATE;
494        }
495    }
496    if (go->bsd_compress) {
497        if (len < CILEN_BSD_COMPRESS
498            || p[0] != CI_BSD_COMPRESS || p[1] != CILEN_BSD_COMPRESS
499            || p[2] != BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits))
500            return 0;
501        p += CILEN_BSD_COMPRESS;
502        len -= CILEN_BSD_COMPRESS;
503        /* XXX Cope with first/fast ack */
504        if (p == p0 && len == 0)
505            return 1;
506    }
507    if (go->predictor_1) {
508        if (len < CILEN_PREDICTOR_1
509            || p[0] != CI_PREDICTOR_1 || p[1] != CILEN_PREDICTOR_1)
510            return 0;
511        p += CILEN_PREDICTOR_1;
512        len -= CILEN_PREDICTOR_1;
513        /* XXX Cope with first/fast ack */
514        if (p == p0 && len == 0)
515            return 1;
516    }
517    if (go->predictor_2) {
518        if (len < CILEN_PREDICTOR_2
519            || p[0] != CI_PREDICTOR_2 || p[1] != CILEN_PREDICTOR_2)
520            return 0;
521        p += CILEN_PREDICTOR_2;
522        len -= CILEN_PREDICTOR_2;
523        /* XXX Cope with first/fast ack */
524        if (p == p0 && len == 0)
525            return 1;
526    }
527
528    if (len != 0)
529        return 0;
530    return 1;
531}
532
533/*
534 * ccp_nakci - process received configure-nak.
535 * Returns 1 iff the nak was OK.
536 */
537static int
538ccp_nakci(f, p, len)
539    fsm *f;
540    u_char *p;
541    int len;
542{
543    ccp_options *go = &ccp_gotoptions[f->unit];
544    ccp_options no;             /* options we've seen already */
545    ccp_options try;            /* options to ask for next time */
546
547    memset(&no, 0, sizeof(no));
548    try = *go;
549
550    if (go->deflate && len >= CILEN_DEFLATE
551        && p[0] == (go->deflate_correct? CI_DEFLATE: CI_DEFLATE_DRAFT)
552        && p[1] == CILEN_DEFLATE) {
553        no.deflate = 1;
554        /*
555         * Peer wants us to use a different code size or something.
556         * Stop asking for Deflate if we don't understand his suggestion.
557         */
558        if (DEFLATE_METHOD(p[2]) != DEFLATE_METHOD_VAL
559            || DEFLATE_SIZE(p[2]) < DEFLATE_MIN_SIZE
560            || p[3] != DEFLATE_CHK_SEQUENCE)
561            try.deflate = 0;
562        else if (DEFLATE_SIZE(p[2]) < go->deflate_size)
563            try.deflate_size = DEFLATE_SIZE(p[2]);
564        p += CILEN_DEFLATE;
565        len -= CILEN_DEFLATE;
566        if (go->deflate_correct && go->deflate_draft
567            && len >= CILEN_DEFLATE && p[0] == CI_DEFLATE_DRAFT
568            && p[1] == CILEN_DEFLATE) {
569            p += CILEN_DEFLATE;
570            len -= CILEN_DEFLATE;
571        }
572    }
573
574    if (go->bsd_compress && len >= CILEN_BSD_COMPRESS
575        && p[0] == CI_BSD_COMPRESS && p[1] == CILEN_BSD_COMPRESS) {
576        no.bsd_compress = 1;
577        /*
578         * Peer wants us to use a different number of bits
579         * or a different version.
580         */
581        if (BSD_VERSION(p[2]) != BSD_CURRENT_VERSION)
582            try.bsd_compress = 0;
583        else if (BSD_NBITS(p[2]) < go->bsd_bits)
584            try.bsd_bits = BSD_NBITS(p[2]);
585        p += CILEN_BSD_COMPRESS;
586        len -= CILEN_BSD_COMPRESS;
587    }
588
589    /*
590     * Predictor-1 and 2 have no options, so they can't be Naked.
591     *
592     * XXX What should we do with any remaining options?
593     */
594
595    if (len != 0)
596        return 0;
597
598    if (f->state != OPENED)
599        *go = try;
600    return 1;
601}
602
603/*
604 * ccp_rejci - reject some of our suggested compression methods.
605 */
606static int
607ccp_rejci(f, p, len)
608    fsm *f;
609    u_char *p;
610    int len;
611{
612    ccp_options *go = &ccp_gotoptions[f->unit];
613    ccp_options try;            /* options to request next time */
614
615    try = *go;
616
617    /*
618     * Cope with empty configure-rejects by ceasing to send
619     * configure-requests.
620     */
621    if (len == 0 && all_rejected[f->unit])
622        return -1;
623
624    if (go->deflate && len >= CILEN_DEFLATE
625        && p[0] == (go->deflate_correct? CI_DEFLATE: CI_DEFLATE_DRAFT)
626        && p[1] == CILEN_DEFLATE) {
627        if (p[2] != DEFLATE_MAKE_OPT(go->deflate_size)
628            || p[3] != DEFLATE_CHK_SEQUENCE)
629            return 0;           /* Rej is bad */
630        if (go->deflate_correct)
631            try.deflate_correct = 0;
632        else
633            try.deflate_draft = 0;
634        p += CILEN_DEFLATE;
635        len -= CILEN_DEFLATE;
636        if (go->deflate_correct && go->deflate_draft
637            && len >= CILEN_DEFLATE && p[0] == CI_DEFLATE_DRAFT
638            && p[1] == CILEN_DEFLATE) {
639            if (p[2] != DEFLATE_MAKE_OPT(go->deflate_size)
640                || p[3] != DEFLATE_CHK_SEQUENCE)
641                return 0;               /* Rej is bad */
642            try.deflate_draft = 0;
643            p += CILEN_DEFLATE;
644            len -= CILEN_DEFLATE;
645        }
646        if (!try.deflate_correct && !try.deflate_draft)
647            try.deflate = 0;
648    }
649    if (go->bsd_compress && len >= CILEN_BSD_COMPRESS
650        && p[0] == CI_BSD_COMPRESS && p[1] == CILEN_BSD_COMPRESS) {
651        if (p[2] != BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits))
652            return 0;
653        try.bsd_compress = 0;
654        p += CILEN_BSD_COMPRESS;
655        len -= CILEN_BSD_COMPRESS;
656    }
657    if (go->predictor_1 && len >= CILEN_PREDICTOR_1
658        && p[0] == CI_PREDICTOR_1 && p[1] == CILEN_PREDICTOR_1) {
659        try.predictor_1 = 0;
660        p += CILEN_PREDICTOR_1;
661        len -= CILEN_PREDICTOR_1;
662    }
663    if (go->predictor_2 && len >= CILEN_PREDICTOR_2
664        && p[0] == CI_PREDICTOR_2 && p[1] == CILEN_PREDICTOR_2) {
665        try.predictor_2 = 0;
666        p += CILEN_PREDICTOR_2;
667        len -= CILEN_PREDICTOR_2;
668    }
669
670    if (len != 0)
671        return 0;
672
673    if (f->state != OPENED)
674        *go = try;
675
676    return 1;
677}
678
679/*
680 * ccp_reqci - processed a received configure-request.
681 * Returns CONFACK, CONFNAK or CONFREJ and the packet modified
682 * appropriately.
683 */
684static int
685ccp_reqci(f, p, lenp, dont_nak)
686    fsm *f;
687    u_char *p;
688    int *lenp;
689    int dont_nak;
690{
691    int ret, newret, res;
692    u_char *p0, *retp;
693    int len, clen, type, nb;
694    ccp_options *ho = &ccp_hisoptions[f->unit];
695    ccp_options *ao = &ccp_allowoptions[f->unit];
696
697    ret = CONFACK;
698    retp = p0 = p;
699    len = *lenp;
700
701    memset(ho, 0, sizeof(ccp_options));
702    ho->method = (len > 0)? p[0]: -1;
703
704    while (len > 0) {
705        newret = CONFACK;
706        if (len < 2 || p[1] < 2 || p[1] > len) {
707            /* length is bad */
708            clen = len;
709            newret = CONFREJ;
710
711        } else {
712            type = p[0];
713            clen = p[1];
714
715            switch (type) {
716            case CI_DEFLATE:
717            case CI_DEFLATE_DRAFT:
718                if (!ao->deflate || clen != CILEN_DEFLATE
719                    || (!ao->deflate_correct && type == CI_DEFLATE)
720                    || (!ao->deflate_draft && type == CI_DEFLATE_DRAFT)) {
721                    newret = CONFREJ;
722                    break;
723                }
724
725                ho->deflate = 1;
726                ho->deflate_size = nb = DEFLATE_SIZE(p[2]);
727                if (DEFLATE_METHOD(p[2]) != DEFLATE_METHOD_VAL
728                    || p[3] != DEFLATE_CHK_SEQUENCE
729                    || nb > ao->deflate_size || nb < DEFLATE_MIN_SIZE) {
730                    newret = CONFNAK;
731                    if (!dont_nak) {
732                        p[2] = DEFLATE_MAKE_OPT(ao->deflate_size);
733                        p[3] = DEFLATE_CHK_SEQUENCE;
734                        /* fall through to test this #bits below */
735                    } else
736                        break;
737                }
738
739                /*
740                 * Check whether we can do Deflate with the window
741                 * size they want.  If the window is too big, reduce
742                 * it until the kernel can cope and nak with that.
743                 * We only check this for the first option.
744                 */
745                if (p == p0) {
746                    for (;;) {
747                        res = ccp_test(f->unit, p, CILEN_DEFLATE, 1);
748                        if (res > 0)
749                            break;              /* it's OK now */
750                        if (res < 0 || nb == DEFLATE_MIN_SIZE || dont_nak) {
751                            newret = CONFREJ;
752                            p[2] = DEFLATE_MAKE_OPT(ho->deflate_size);
753                            break;
754                        }
755                        newret = CONFNAK;
756                        --nb;
757                        p[2] = DEFLATE_MAKE_OPT(nb);
758                    }
759                }
760                break;
761
762            case CI_BSD_COMPRESS:
763                if (!ao->bsd_compress || clen != CILEN_BSD_COMPRESS) {
764                    newret = CONFREJ;
765                    break;
766                }
767
768                ho->bsd_compress = 1;
769                ho->bsd_bits = nb = BSD_NBITS(p[2]);
770                if (BSD_VERSION(p[2]) != BSD_CURRENT_VERSION
771                    || nb > ao->bsd_bits || nb < BSD_MIN_BITS) {
772                    newret = CONFNAK;
773                    if (!dont_nak) {
774                        p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, ao->bsd_bits);
775                        /* fall through to test this #bits below */
776                    } else
777                        break;
778                }
779
780                /*
781                 * Check whether we can do BSD-Compress with the code
782                 * size they want.  If the code size is too big, reduce
783                 * it until the kernel can cope and nak with that.
784                 * We only check this for the first option.
785                 */
786                if (p == p0) {
787                    for (;;) {
788                        res = ccp_test(f->unit, p, CILEN_BSD_COMPRESS, 1);
789                        if (res > 0)
790                            break;
791                        if (res < 0 || nb == BSD_MIN_BITS || dont_nak) {
792                            newret = CONFREJ;
793                            p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION,
794                                                ho->bsd_bits);
795                            break;
796                        }
797                        newret = CONFNAK;
798                        --nb;
799                        p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, nb);
800                    }
801                }
802                break;
803
804            case CI_PREDICTOR_1:
805                if (!ao->predictor_1 || clen != CILEN_PREDICTOR_1) {
806                    newret = CONFREJ;
807                    break;
808                }
809
810                ho->predictor_1 = 1;
811                if (p == p0
812                    && ccp_test(f->unit, p, CILEN_PREDICTOR_1, 1) <= 0) {
813                    newret = CONFREJ;
814                }
815                break;
816
817            case CI_PREDICTOR_2:
818                if (!ao->predictor_2 || clen != CILEN_PREDICTOR_2) {
819                    newret = CONFREJ;
820                    break;
821                }
822
823                ho->predictor_2 = 1;
824                if (p == p0
825                    && ccp_test(f->unit, p, CILEN_PREDICTOR_2, 1) <= 0) {
826                    newret = CONFREJ;
827                }
828                break;
829
830            default:
831                newret = CONFREJ;
832            }
833        }
834
835        if (newret == CONFNAK && dont_nak)
836            newret = CONFREJ;
837        if (!(newret == CONFACK || (newret == CONFNAK && ret == CONFREJ))) {
838            /* we're returning this option */
839            if (newret == CONFREJ && ret == CONFNAK)
840                retp = p0;
841            ret = newret;
842            if (p != retp)
843                BCOPY(p, retp, clen);
844            retp += clen;
845        }
846
847        p += clen;
848        len -= clen;
849    }
850
851    if (ret != CONFACK) {
852        if (ret == CONFREJ && *lenp == retp - p0)
853            all_rejected[f->unit] = 1;
854        else
855            *lenp = retp - p0;
856    }
857    return ret;
858}
859
860/*
861 * Make a string name for a compression method (or 2).
862 */
863static char *
864method_name(opt, opt2)
865    ccp_options *opt, *opt2;
866{
867    static char result[64];
868
869    if (!ANY_COMPRESS(*opt))
870        return "(none)";
871    switch (opt->method) {
872    case CI_DEFLATE:
873    case CI_DEFLATE_DRAFT:
874        if (opt2 != NULL && opt2->deflate_size != opt->deflate_size)
875            sprintf(result, "Deflate%s (%d/%d)",
876                    (opt->method == CI_DEFLATE_DRAFT? "(old#)": ""),
877                    opt->deflate_size, opt2->deflate_size);
878        else
879            sprintf(result, "Deflate%s (%d)",
880                    (opt->method == CI_DEFLATE_DRAFT? "(old#)": ""),
881                    opt->deflate_size);
882        break;
883    case CI_BSD_COMPRESS:
884        if (opt2 != NULL && opt2->bsd_bits != opt->bsd_bits)
885            sprintf(result, "BSD-Compress (%d/%d)", opt->bsd_bits,
886                    opt2->bsd_bits);
887        else
888            sprintf(result, "BSD-Compress (%d)", opt->bsd_bits);
889        break;
890    case CI_PREDICTOR_1:
891        return "Predictor 1";
892    case CI_PREDICTOR_2:
893        return "Predictor 2";
894    default:
895        sprintf(result, "Method %d", opt->method);
896    }
897    return result;
898}
899
900/*
901 * CCP has come up - inform the kernel driver and log a message.
902 */
903static void
904ccp_up(f)
905    fsm *f;
906{
907    ccp_options *go = &ccp_gotoptions[f->unit];
908    ccp_options *ho = &ccp_hisoptions[f->unit];
909    char method1[64];
910
911    ccp_flags_set(f->unit, 1, 1);
912    if (ANY_COMPRESS(*go)) {
913        if (ANY_COMPRESS(*ho)) {
914            if (go->method == ho->method) {
915                syslog(LOG_NOTICE, "%s compression enabled",
916                       method_name(go, ho))
917;
918            } else {
919                strcpy(method1, method_name(go, NULL));
920                syslog(LOG_NOTICE, "%s / %s compression enabled",
921                       method1, method_name(ho, NULL))
922;
923            }
924        } else
925            syslog(LOG_NOTICE, "%s receive compression enabled",
926                   method_name(go, NULL))
927;
928    } else if (ANY_COMPRESS(*ho))
929        syslog(LOG_NOTICE, "%s transmit compression enabled",
930               method_name(ho, NULL))
931;
932}
933
934/*
935 * CCP has gone down - inform the kernel driver.
936 */
937static void
938ccp_down(f)
939    fsm *f;
940{
941    if (ccp_localstate[f->unit] & RACK_PENDING)
942        UNTIMEOUT(ccp_rack_timeout, f);
943    ccp_localstate[f->unit] = 0;
944    ccp_flags_set(f->unit, 1, 0);
945}
946
947/*
948 * Print the contents of a CCP packet.
949 */
950static char *ccp_codenames[] = {
951    "ConfReq", "ConfAck", "ConfNak", "ConfRej",
952    "TermReq", "TermAck", "CodeRej",
953    NULL, NULL, NULL, NULL, NULL, NULL,
954    "ResetReq", "ResetAck",
955};
956
957static int
958ccp_printpkt(p, plen, printer, arg)
959    u_char *p;
960    int plen;
961    void (*printer) __P((void *, char *, ...));
962    void *arg;
963{
964    u_char *p0, *optend;
965    int code, id, len;
966    int optlen;
967
968    p0 = p;
969    if (plen < HEADERLEN)
970        return 0;
971    code = p[0];
972    id = p[1];
973    len = (p[2] << 8) + p[3];
974    if (len < HEADERLEN || len > plen)
975        return 0;
976
977    if (code >= 1 && code <= sizeof(ccp_codenames) / sizeof(char *)
978        && ccp_codenames[code-1] != NULL)
979        printer(arg, " %s", ccp_codenames[code-1]);
980    else
981        printer(arg, " code=0x%x", code);
982    printer(arg, " id=0x%x", id);
983    len -= HEADERLEN;
984    p += HEADERLEN;
985
986    switch (code) {
987    case CONFREQ:
988    case CONFACK:
989    case CONFNAK:
990    case CONFREJ:
991        /* print list of possible compression methods */
992        while (len >= 2) {
993            code = p[0];
994            optlen = p[1];
995            if (optlen < 2 || optlen > len)
996                break;
997            printer(arg, " <");
998            len -= optlen;
999            optend = p + optlen;
1000            switch (code) {
1001            case CI_DEFLATE:
1002            case CI_DEFLATE_DRAFT:
1003                if (optlen >= CILEN_DEFLATE) {
1004                    printer(arg, "deflate%s %d",
1005                            (code == CI_DEFLATE_DRAFT? "(old#)": ""),
1006                            DEFLATE_SIZE(p[2]));
1007                    if (DEFLATE_METHOD(p[2]) != DEFLATE_METHOD_VAL)
1008                        printer(arg, " method %d", DEFLATE_METHOD(p[2]));
1009                    if (p[3] != DEFLATE_CHK_SEQUENCE)
1010                        printer(arg, " check %d", p[3]);
1011                    p += CILEN_DEFLATE;
1012                }
1013                break;
1014            case CI_BSD_COMPRESS:
1015                if (optlen >= CILEN_BSD_COMPRESS) {
1016                    printer(arg, "bsd v%d %d", BSD_VERSION(p[2]),
1017                            BSD_NBITS(p[2]));
1018                    p += CILEN_BSD_COMPRESS;
1019                }
1020                break;
1021            case CI_PREDICTOR_1:
1022                if (optlen >= CILEN_PREDICTOR_1) {
1023                    printer(arg, "predictor 1");
1024                    p += CILEN_PREDICTOR_1;
1025                }
1026                break;
1027            case CI_PREDICTOR_2:
1028                if (optlen >= CILEN_PREDICTOR_2) {
1029                    printer(arg, "predictor 2");
1030                    p += CILEN_PREDICTOR_2;
1031                }
1032                break;
1033            }
1034/*          while (p < optend)
1035                printer(arg, " %.2x", *p++);
1036            printer(arg, ">");
1037*/      }
1038        break;
1039
1040    case TERMACK:
1041    case TERMREQ:
1042/*      if (len > 0 && *p >= ' ' && *p < 0x7f) {
1043            print_string(p, len, printer, arg);
1044            p += len;
1045            len = 0;
1046        }
1047*/      break;
1048    }
1049
1050    /* dump out the rest of the packet in hex */
1051/*    while (--len >= 0)
1052        printer(arg, " %.2x", *p++);
1053*/
1054    return p - p0;
1055}
1056
1057/*
1058 * We have received a packet that the decompressor failed to
1059 * decompress.  Here we would expect to issue a reset-request, but
1060 * Motorola has a patent on resetting the compressor as a result of
1061 * detecting an error in the decompressed data after decompression.
1062 * (See US patent 5,130,993; international patent publication number
1063 * WO 91/10289; Australian patent 73296/91.)
1064 *
1065 * So we ask the kernel whether the error was detected after
1066 * decompression; if it was, we take CCP down, thus disabling
1067 * compression :-(, otherwise we issue the reset-request.
1068 */
1069static void
1070ccp_datainput(unit, pkt, len)
1071    int unit;
1072    u_char *pkt;
1073    int len;
1074{
1075    fsm *f;
1076
1077    f = &ccp_fsm[unit];
1078    if (f->state == OPENED) {
1079        if (ccp_fatal_error(unit)) {
1080            /*
1081             * Disable compression by taking CCP down.
1082             */
1083            syslog(LOG_ERR, "Lost compression sync: disabling compression");
1084            ccp_close(unit, "Lost compression sync");
1085        } else {
1086            /*
1087             * Send a reset-request to reset the peer's compressor.
1088             * We don't do that if we are still waiting for an
1089             * acknowledgement to a previous reset-request.
1090             */
1091            if (!(ccp_localstate[f->unit] & RACK_PENDING)) {
1092                fsm_sdata(f, CCP_RESETREQ, f->reqid = ++f->id, NULL, 0);
1093                TIMEOUT(ccp_rack_timeout, f, RACKTIMEOUT);
1094                ccp_localstate[f->unit] |= RACK_PENDING;
1095            } else
1096                ccp_localstate[f->unit] |= RREQ_REPEAT;
1097        }
1098    }
1099}
1100
1101/*
1102 * Timeout waiting for reset-ack.
1103 */
1104static void
1105ccp_rack_timeout(arg)
1106    void *arg;
1107{
1108    fsm *f = arg;
1109
1110    if (f->state == OPENED && ccp_localstate[f->unit] & RREQ_REPEAT) {
1111        fsm_sdata(f, CCP_RESETREQ, f->reqid, NULL, 0);
1112        TIMEOUT(ccp_rack_timeout, f, RACKTIMEOUT);
1113        ccp_localstate[f->unit] &= ~RREQ_REPEAT;
1114    } else
1115        ccp_localstate[f->unit] &= ~RACK_PENDING;
1116}
1117
Note: See TracBrowser for help on using the repository browser.