source: rtems-libbsd/rtemsbsd/pppd/ccp.c

6-freebsd-12
Last change on this file was 70fa95a, checked in by Sebastian Huber <sebastian.huber@…>, on 09/30/14 at 12:46:12

ppp: Import from RTEMS sources

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