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