]> git.ozlabs.org Git - ppp.git/blob - pppd/ccp.c
NetBSD-1.1 files
[ppp.git] / pppd / ccp.c
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: ccp.c,v 1.12 1995/10/27 03:42:52 paulus Exp $";
30 #endif
31
32 #include <syslog.h>
33 #include <sys/ioctl.h>
34 #include <net/ppp-comp.h>
35
36 #include "pppd.h"
37 #include "fsm.h"
38 #include "ccp.h"
39
40 fsm ccp_fsm[NUM_PPP];
41 ccp_options ccp_wantoptions[NUM_PPP];   /* what to request the peer to use */
42 ccp_options ccp_gotoptions[NUM_PPP];    /* what the peer agreed to do */
43 ccp_options ccp_allowoptions[NUM_PPP];  /* what we'll agree to do */
44 ccp_options ccp_hisoptions[NUM_PPP];    /* what we agreed to do */
45
46 /*
47  * Callbacks for fsm code.
48  */
49 static void ccp_resetci __P((fsm *));
50 static int  ccp_cilen __P((fsm *));
51 static void ccp_addci __P((fsm *, u_char *, int *));
52 static int  ccp_ackci __P((fsm *, u_char *, int));
53 static int  ccp_nakci __P((fsm *, u_char *, int));
54 static int  ccp_rejci __P((fsm *, u_char *, int));
55 static int  ccp_reqci __P((fsm *, u_char *, int *, int));
56 static void ccp_up __P((fsm *));
57 static void ccp_down __P((fsm *));
58 static int  ccp_extcode __P((fsm *, int, int, u_char *, int));
59 static void ccp_rack_timeout __P(());
60
61 static fsm_callbacks ccp_callbacks = {
62     ccp_resetci,
63     ccp_cilen,
64     ccp_addci,
65     ccp_ackci,
66     ccp_nakci,
67     ccp_rejci,
68     ccp_reqci,
69     ccp_up,
70     ccp_down,
71     NULL,
72     NULL,
73     NULL,
74     NULL,
75     ccp_extcode,
76     "CCP"
77 };
78
79 /*
80  * Do we want / did we get any compression?
81  */
82 #define ANY_COMPRESS(opt)       ((opt).deflate || (opt).bsd_compress \
83                                  || (opt).predictor_1 || (opt).predictor_2)
84
85 /*
86  * Local state (mainly for handling reset-reqs and reset-acks).
87  */
88 static int ccp_localstate[NUM_PPP];
89 #define RACK_PENDING    1       /* waiting for reset-ack */
90 #define RREQ_REPEAT     2       /* send another reset-req if no reset-ack */
91
92 #define RACKTIMEOUT     1       /* second */
93
94 static int all_rejected[NUM_PPP];       /* we rejected all peer's options */
95
96 /*
97  * ccp_init - initialize CCP.
98  */
99 void
100 ccp_init(unit)
101     int unit;
102 {
103     fsm *f = &ccp_fsm[unit];
104
105     f->unit = unit;
106     f->protocol = PPP_CCP;
107     f->callbacks = &ccp_callbacks;
108     fsm_init(f);
109
110     memset(&ccp_wantoptions[unit],  0, sizeof(ccp_options));
111     memset(&ccp_gotoptions[unit],   0, sizeof(ccp_options));
112     memset(&ccp_allowoptions[unit], 0, sizeof(ccp_options));
113     memset(&ccp_hisoptions[unit],   0, sizeof(ccp_options));
114
115     ccp_wantoptions[0].bsd_compress = 1;
116     ccp_wantoptions[0].bsd_bits = 12;   /* default value */
117
118     ccp_allowoptions[0].bsd_compress = 1;
119     ccp_allowoptions[0].bsd_bits = BSD_MAX_BITS;
120 }
121
122 /*
123  * ccp_open - CCP is allowed to come up.
124  */
125 void
126 ccp_open(unit)
127     int unit;
128 {
129     fsm *f = &ccp_fsm[unit];
130
131     if (f->state != OPENED)
132         ccp_flags_set(unit, 1, 0);
133     if (!ANY_COMPRESS(ccp_wantoptions[unit]))
134         f->flags |= OPT_SILENT;
135     fsm_open(f);
136 }
137
138 /*
139  * ccp_close - Terminate CCP.
140  */
141 void
142 ccp_close(unit)
143     int unit;
144 {
145     ccp_flags_set(unit, 0, 0);
146     fsm_close(&ccp_fsm[unit]);
147 }
148
149 /*
150  * ccp_lowerup - we may now transmit CCP packets.
151  */
152 void
153 ccp_lowerup(unit)
154     int unit;
155 {
156     fsm_lowerup(&ccp_fsm[unit]);
157 }
158
159 /*
160  * ccp_lowerdown - we may not transmit CCP packets.
161  */
162 void
163 ccp_lowerdown(unit)
164     int unit;
165 {
166     fsm_lowerdown(&ccp_fsm[unit]);
167 }
168
169 /*
170  * ccp_input - process a received CCP packet.
171  */
172 void
173 ccp_input(unit, p, len)
174     int unit;
175     u_char *p;
176     int len;
177 {
178     fsm *f = &ccp_fsm[unit];
179     int oldstate;
180
181     /*
182      * Check for a terminate-request so we can print a message.
183      */
184     oldstate = f->state;
185     fsm_input(f, p, len);
186     if (oldstate == OPENED && p[0] == TERMREQ && f->state != OPENED)
187         syslog(LOG_NOTICE, "Compression disabled by peer.");
188
189     /*
190      * If we get a terminate-ack and we're not asking for compression,
191      * close CCP.
192      */
193     if (oldstate == REQSENT && p[0] == TERMACK
194         && !ANY_COMPRESS(ccp_gotoptions[unit]))
195         ccp_close(unit);
196 }
197
198 /*
199  * Handle a CCP-specific code.
200  */
201 static int
202 ccp_extcode(f, code, id, p, len)
203     fsm *f;
204     int code, id;
205     u_char *p;
206     int len;
207 {
208     switch (code) {
209     case CCP_RESETREQ:
210         if (f->state != OPENED)
211             break;
212         /* send a reset-ack, which the transmitter will see and
213            reset its compression state. */
214         fsm_sdata(f, CCP_RESETACK, id, NULL, 0);
215         break;
216
217     case CCP_RESETACK:
218         if (ccp_localstate[f->unit] & RACK_PENDING && id == f->reqid) {
219             ccp_localstate[f->unit] &= ~(RACK_PENDING | RREQ_REPEAT);
220             UNTIMEOUT(ccp_rack_timeout, (caddr_t) f);
221         }
222         break;
223
224     default:
225         return 0;
226     }
227
228     return 1;
229 }
230
231 /*
232  * ccp_protrej - peer doesn't talk CCP.
233  */
234 void
235 ccp_protrej(unit)
236     int unit;
237 {
238     ccp_flags_set(unit, 0, 0);
239     fsm_lowerdown(&ccp_fsm[unit]);
240 }
241
242 /*
243  * ccp_resetci - initialize at start of negotiation.
244  */
245 static void
246 ccp_resetci(f)
247     fsm *f;
248 {
249     int ok;
250     ccp_options *go = &ccp_gotoptions[f->unit];
251     u_char opt_buf[16];
252
253     *go = ccp_wantoptions[f->unit];
254     all_rejected[f->unit] = 0;
255
256     /*
257      * Check whether the kernel knows about the various
258      * compression methods we might request.
259      */
260     if (go->bsd_compress) {
261         opt_buf[0] = CI_BSD_COMPRESS;
262         opt_buf[1] = CILEN_BSD_COMPRESS;
263         opt_buf[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, BSD_MIN_BITS);
264         if (ccp_test(f->unit, opt_buf, CILEN_BSD_COMPRESS, 0) <= 0)
265             go->bsd_compress = 0;
266     }
267     if (go->deflate) {
268         opt_buf[0] = CI_DEFLATE;
269         opt_buf[1] = CILEN_DEFLATE;
270         opt_buf[2] = DEFLATE_MAKE_OPT(DEFLATE_MIN_SIZE);
271         opt_buf[3] = DEFLATE_CHK_SEQUENCE;
272         if (ccp_test(f->unit, opt_buf, CILEN_DEFLATE, 0) <= 0)
273             go->deflate = 0;
274     }
275     if (go->predictor_1) {
276         opt_buf[0] = CI_PREDICTOR_1;
277         opt_buf[1] = CILEN_PREDICTOR_1;
278         if (ccp_test(f->unit, opt_buf, CILEN_PREDICTOR_1, 0) <= 0)
279             go->predictor_1 = 0;
280     }
281     if (go->predictor_2) {
282         opt_buf[0] = CI_PREDICTOR_2;
283         opt_buf[1] = CILEN_PREDICTOR_2;
284         if (ccp_test(f->unit, opt_buf, CILEN_PREDICTOR_2, 0) <= 0)
285             go->predictor_2 = 0;
286     }
287 }
288
289 /*
290  * ccp_cilen - Return total length of our configuration info.
291  */
292 static int
293 ccp_cilen(f)
294     fsm *f;
295 {
296     ccp_options *go = &ccp_gotoptions[f->unit];
297
298     return (go->bsd_compress? CILEN_BSD_COMPRESS: 0)
299         + (go->deflate? CILEN_DEFLATE: 0)
300         + (go->predictor_1? CILEN_PREDICTOR_1: 0)
301         + (go->predictor_2? CILEN_PREDICTOR_2: 0);
302 }
303
304 /*
305  * ccp_addci - put our requests in a packet.
306  */
307 static void
308 ccp_addci(f, p, lenp)
309     fsm *f;
310     u_char *p;
311     int *lenp;
312 {
313     int res;
314     ccp_options *go = &ccp_gotoptions[f->unit];
315     u_char *p0 = p;
316
317     /*
318      * Add the compression types that we can receive, in decreasing
319      * preference order.  Get the kernel to allocate the first one
320      * in case it gets Acked.
321      */
322     if (go->deflate) {
323         p[0] = CI_DEFLATE;
324         p[1] = CILEN_DEFLATE;
325         p[2] = DEFLATE_MAKE_OPT(go->deflate_size);
326         p[3] = DEFLATE_CHK_SEQUENCE;
327         for (;;) {
328             res = ccp_test(f->unit, p, CILEN_DEFLATE, 0);
329             if (res > 0) {
330                 p += CILEN_DEFLATE;
331                 break;
332             }
333             if (res < 0 || go->deflate_size <= DEFLATE_MIN_SIZE) {
334                 go->deflate = 0;
335                 break;
336             }
337             --go->deflate_size;
338             p[2] = DEFLATE_MAKE_OPT(go->deflate_size);
339         }
340     }
341     if (go->bsd_compress) {
342         p[0] = CI_BSD_COMPRESS;
343         p[1] = CILEN_BSD_COMPRESS;
344         p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits);
345         if (p != p0) {
346             p += CILEN_BSD_COMPRESS;    /* not the first option */
347         } else {
348             for (;;) {
349                 res = ccp_test(f->unit, p, CILEN_BSD_COMPRESS, 0);
350                 if (res > 0) {
351                     p += CILEN_BSD_COMPRESS;
352                     break;
353                 }
354                 if (res < 0 || go->bsd_bits <= BSD_MIN_BITS) {
355                     go->bsd_compress = 0;
356                     break;
357                 }
358                 --go->bsd_bits;
359                 p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits);
360             }
361         }
362     }
363     /* XXX Should Predictor 2 be preferable to Predictor 1? */
364     if (go->predictor_1) {
365         p[0] = CI_PREDICTOR_1;
366         p[1] = CILEN_PREDICTOR_1;
367         if (p == p0 && ccp_test(f->unit, p, CILEN_PREDICTOR_1, 0) <= 0) {
368             go->predictor_1 = 0;
369         } else {
370             p += CILEN_PREDICTOR_1;
371         }
372     }
373     if (go->predictor_2) {
374         p[0] = CI_PREDICTOR_2;
375         p[1] = CILEN_PREDICTOR_2;
376         if (p == p0 && ccp_test(f->unit, p, CILEN_PREDICTOR_2, 0) <= 0) {
377             go->predictor_2 = 0;
378         } else {
379             p += CILEN_PREDICTOR_2;
380         }
381     }
382
383     *lenp = p - p0;
384 }
385
386 /*
387  * ccp_ackci - process a received configure-ack, and return
388  * 1 iff the packet was OK.
389  */
390 static int
391 ccp_ackci(f, p, len)
392     fsm *f;
393     u_char *p;
394     int len;
395 {
396     ccp_options *go = &ccp_gotoptions[f->unit];
397     u_char *p0 = p;
398
399     if (go->deflate) {
400         if (len < CILEN_DEFLATE
401             || p[0] != CI_DEFLATE || p[1] != CILEN_DEFLATE
402             || p[2] != DEFLATE_MAKE_OPT(go->deflate_size)
403             || p[3] != DEFLATE_CHK_SEQUENCE)
404             return 0;
405         p += CILEN_DEFLATE;
406         len -= CILEN_DEFLATE;
407         /* XXX Cope with first/fast ack */
408         if (len == 0)
409             return 1;
410     }
411     if (go->bsd_compress) {
412         if (len < CILEN_BSD_COMPRESS
413             || p[0] != CI_BSD_COMPRESS || p[1] != CILEN_BSD_COMPRESS
414             || p[2] != BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits))
415             return 0;
416         p += CILEN_BSD_COMPRESS;
417         len -= CILEN_BSD_COMPRESS;
418         /* XXX Cope with first/fast ack */
419         if (p == p0 && len == 0)
420             return 1;
421     }
422     if (go->predictor_1) {
423         if (len < CILEN_PREDICTOR_1
424             || p[0] != CI_PREDICTOR_1 || p[1] != CILEN_PREDICTOR_1)
425             return 0;
426         /* XXX Cope with first/fast ack */
427         if (p == p0 && len == 0)
428             return 1;
429     }
430     if (go->predictor_2) {
431         if (len < CILEN_PREDICTOR_2
432             || p[0] != CI_PREDICTOR_2 || p[1] != CILEN_PREDICTOR_2)
433             return 0;
434         /* XXX Cope with first/fast ack */
435         if (p == p0 && len == 0)
436             return 1;
437     }
438
439     if (len != 0)
440         return 0;
441     return 1;
442 }
443
444 /*
445  * ccp_nakci - process received configure-nak.
446  * Returns 1 iff the nak was OK.
447  */
448 static int
449 ccp_nakci(f, p, len)
450     fsm *f;
451     u_char *p;
452     int len;
453 {
454     ccp_options *go = &ccp_gotoptions[f->unit];
455     ccp_options no;             /* options we've seen already */
456     ccp_options try;            /* options to ask for next time */
457
458     memset(&no, 0, sizeof(no));
459     try = *go;
460
461     if (go->deflate && len >= CILEN_DEFLATE
462         && p[0] == CI_DEFLATE && p[1] == CILEN_DEFLATE) {
463         no.deflate = 1;
464         /*
465          * Peer wants us to use a different code size or something.
466          * Stop asking for Deflate if we don't understand his suggestion.
467          */
468         if (DEFLATE_METHOD(p[2]) != DEFLATE_METHOD_VAL
469             || DEFLATE_SIZE(p[2]) < DEFLATE_MIN_SIZE
470             || p[3] != DEFLATE_CHK_SEQUENCE)
471             try.deflate = 0;
472         else if (DEFLATE_SIZE(p[2]) < go->deflate_size)
473             go->deflate_size = DEFLATE_SIZE(p[2]);
474         p += CILEN_DEFLATE;
475         len -= CILEN_DEFLATE;
476     }
477
478     if (go->bsd_compress && len >= CILEN_BSD_COMPRESS
479         && p[0] == CI_BSD_COMPRESS && p[1] == CILEN_BSD_COMPRESS) {
480         no.bsd_compress = 1;
481         /*
482          * Peer wants us to use a different number of bits
483          * or a different version.
484          */
485         if (BSD_VERSION(p[2]) != BSD_CURRENT_VERSION)
486             try.bsd_compress = 0;
487         else if (BSD_NBITS(p[2]) < go->bsd_bits)
488             try.bsd_bits = BSD_NBITS(p[2]);
489         p += CILEN_BSD_COMPRESS;
490         len -= CILEN_BSD_COMPRESS;
491     }
492
493     /*
494      * Predictor-1 and 2 have no options, so they can't be Naked.
495      *
496      * XXX What should we do with any remaining options?
497      */
498
499     if (len != 0)
500         return 0;
501
502     if (f->state != OPENED)
503         *go = try;
504     return 1;
505 }
506
507 /*
508  * ccp_rejci - reject some of our suggested compression methods.
509  */
510 static int
511 ccp_rejci(f, p, len)
512     fsm *f;
513     u_char *p;
514     int len;
515 {
516     ccp_options *go = &ccp_gotoptions[f->unit];
517     ccp_options try;            /* options to request next time */
518
519     try = *go;
520
521     /*
522      * Cope with empty configure-rejects by ceasing to send
523      * configure-requests.
524      */
525     if (len == 0 && all_rejected[f->unit])
526         return -1;
527
528     if (go->deflate && len >= CILEN_DEFLATE
529         && p[0] == CI_DEFLATE && p[1] == CILEN_DEFLATE) {
530         if (p[2] != DEFLATE_MAKE_OPT(go->deflate_size)
531             || p[3] != DEFLATE_CHK_SEQUENCE)
532             return 0;           /* Rej is bad */
533         try.deflate = 0;
534         p += CILEN_DEFLATE;
535         len -= CILEN_DEFLATE;
536     }
537     if (go->bsd_compress && len >= CILEN_BSD_COMPRESS
538         && p[0] == CI_BSD_COMPRESS && p[1] == CILEN_BSD_COMPRESS) {
539         if (p[2] != BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits))
540             return 0;
541         try.bsd_compress = 0;
542         p += CILEN_BSD_COMPRESS;
543         len -= CILEN_BSD_COMPRESS;
544     }
545     if (go->predictor_1 && len >= CILEN_PREDICTOR_1
546         && p[0] == CI_PREDICTOR_1 && p[1] == CILEN_PREDICTOR_1) {
547         try.predictor_1 = 0;
548         p += CILEN_PREDICTOR_1;
549         len -= CILEN_PREDICTOR_1;
550     }
551     if (go->predictor_2 && len >= CILEN_PREDICTOR_2
552         && p[0] == CI_PREDICTOR_2 && p[1] == CILEN_PREDICTOR_2) {
553         try.predictor_2 = 0;
554         p += CILEN_PREDICTOR_2;
555         len -= CILEN_PREDICTOR_2;
556     }
557
558     if (len != 0)
559         return 0;
560
561     if (f->state != OPENED)
562         *go = try;
563
564     return 1;
565 }
566
567 /*
568  * ccp_reqci - processed a received configure-request.
569  * Returns CONFACK, CONFNAK or CONFREJ and the packet modified
570  * appropriately.
571  */
572 static int
573 ccp_reqci(f, p, lenp, dont_nak)
574     fsm *f;
575     u_char *p;
576     int *lenp;
577     int dont_nak;
578 {
579     int ret, newret, res;
580     u_char *p0, *retp;
581     int len, clen, type, nb;
582     ccp_options *ho = &ccp_hisoptions[f->unit];
583     ccp_options *ao = &ccp_allowoptions[f->unit];
584
585     ret = CONFACK;
586     retp = p0 = p;
587     len = *lenp;
588
589     memset(ho, 0, sizeof(ccp_options));
590
591     while (len > 0) {
592         newret = CONFACK;
593         if (len < 2 || p[1] < 2 || p[1] > len) {
594             /* length is bad */
595             clen = len;
596             newret = CONFREJ;
597
598         } else {
599             type = p[0];
600             clen = p[1];
601
602             switch (type) {
603             case CI_DEFLATE:
604                 if (!ao->deflate || clen != CILEN_DEFLATE) {
605                     newret = CONFREJ;
606                     break;
607                 }
608
609                 ho->deflate = 1;
610                 ho->deflate_size = nb = DEFLATE_SIZE(p[2]);
611                 if (DEFLATE_METHOD(p[2]) != DEFLATE_METHOD_VAL
612                     || p[3] != DEFLATE_CHK_SEQUENCE
613                     || nb > ao->deflate_size) {
614                     newret = CONFNAK;
615                     nb = ao->deflate_size;
616                 } else {
617                     /*
618                      * Check whether we can do Deflate with the window
619                      * size they want.  If the window is too big, reduce
620                      * it until the kernel can cope and nak with that.
621                      */
622                     for (;;) {
623                         if (nb < DEFLATE_MIN_SIZE) {
624                             newret = CONFREJ;
625                             p[2] = DEFLATE_MAKE_OPT(ho->deflate_size);
626                             break;
627                         }
628                         p[2] = DEFLATE_MAKE_OPT(nb);
629                         res = ccp_test(f->unit, p, CILEN_DEFLATE, 1);
630                         if (res != 0) {
631                             if (res < 0)
632                                 newret = CONFREJ;
633                             break;
634                         }
635                         newret = CONFNAK;
636                         --nb;
637                     }
638                 }
639                 if (newret == CONFNAK && !dont_nak) {
640                     if (nb >= DEFLATE_MIN_SIZE) {
641                         p[2] = DEFLATE_MAKE_OPT(nb);
642                         p[3] = DEFLATE_CHK_SEQUENCE;
643                     } else {
644                         newret = CONFREJ;
645                     }
646                 }
647                 break;
648
649             case CI_BSD_COMPRESS:
650                 if (!ao->bsd_compress || clen != CILEN_BSD_COMPRESS) {
651                     newret = CONFREJ;
652                     break;
653                 }
654
655                 ho->bsd_compress = 1;
656                 ho->bsd_bits = nb = BSD_NBITS(p[2]);
657                 if (BSD_VERSION(p[2]) != BSD_CURRENT_VERSION
658                     || nb > ao->bsd_bits) {
659                     newret = CONFNAK;
660                     nb = ao->bsd_bits;
661                 } else {
662                     /*
663                      * Check whether we can do BSD_Compress with the code
664                      * size they want.  If the code size is too big, reduce
665                      * it until the kernel can cope and nak with that.
666                      */
667                     for (;;) {
668                         if (nb < BSD_MIN_BITS) {
669                             newret = CONFREJ;
670                             p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION,
671                                                 ho->bsd_bits);
672                             break;
673                         }
674                         p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, nb);
675                         res = ccp_test(f->unit, p, CILEN_BSD_COMPRESS, 1);
676                         if (res != 0) {
677                             if (res < 0)
678                                 newret = CONFREJ;
679                             break;
680                         }
681                         newret = CONFNAK;
682                         --nb;
683                     }
684                 }
685                 if (newret == CONFNAK && !dont_nak) {
686                     if (nb >= BSD_MIN_BITS) {
687                         p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, nb);
688                     } else {
689                         newret = CONFREJ;
690                     }
691                 }
692                 break;
693
694             case CI_PREDICTOR_1:
695                 if (!ao->predictor_1 || clen != CILEN_PREDICTOR_1) {
696                     newret = CONFREJ;
697                     break;
698                 }
699
700                 ho->predictor_1 = 1;
701                 if (ccp_test(f->unit, p, CILEN_PREDICTOR_1, 1) <= 0) {
702                     newret = CONFREJ;
703                 }
704                 break;
705
706             case CI_PREDICTOR_2:
707                 if (!ao->predictor_2 || clen != CILEN_PREDICTOR_2) {
708                     newret = CONFREJ;
709                     break;
710                 }
711
712                 ho->predictor_2 = 1;
713                 if (ccp_test(f->unit, p, CILEN_PREDICTOR_2, 1) <= 0) {
714                     newret = CONFREJ;
715                 }
716                 break;
717
718             default:
719                 newret = CONFREJ;
720             }
721         }
722
723         if (newret == CONFNAK && dont_nak)
724             newret = CONFREJ;
725         if (!(newret == CONFACK || newret == CONFNAK && ret == CONFREJ)) {
726             /* we're returning this option */
727             if (newret == CONFREJ && ret == CONFNAK)
728                 retp = p0;
729             ret = newret;
730             if (p != retp)
731                 BCOPY(p, retp, clen);
732             retp += clen;
733         }
734
735         p += clen;
736         len -= clen;
737     }
738
739     if (ret != CONFACK) {
740         if (ret == CONFREJ && *lenp == retp - p0)
741             all_rejected[f->unit] = 1;
742         else
743             *lenp = retp - p0;
744     }
745     return ret;
746 }
747
748 /*
749  * CCP has come up - inform the kernel driver.
750  */
751 static void
752 ccp_up(f)
753     fsm *f;
754 {
755     ccp_options *go = &ccp_gotoptions[f->unit];
756     ccp_options *ho = &ccp_hisoptions[f->unit];
757
758     ccp_flags_set(f->unit, 1, 1);
759     if (ANY_COMPRESS(*go) || ANY_COMPRESS(*ho))
760         syslog(LOG_NOTICE, "%s enabled",
761                ANY_COMPRESS(*go)? ANY_COMPRESS(*ho)? "Compression":
762                "Receive compression": "Transmit compression");
763 }
764
765 /*
766  * CCP has gone down - inform the kernel driver.
767  */
768 static void
769 ccp_down(f)
770     fsm *f;
771 {
772     if (ccp_localstate[f->unit] & RACK_PENDING)
773         UNTIMEOUT(ccp_rack_timeout, (caddr_t) f);
774     ccp_localstate[f->unit] = 0;
775     ccp_flags_set(f->unit, 1, 0);
776 }
777
778 /*
779  * Print the contents of a CCP packet.
780  */
781 char *ccp_codenames[] = {
782     "ConfReq", "ConfAck", "ConfNak", "ConfRej",
783     "TermReq", "TermAck", "CodeRej",
784     NULL, NULL, NULL, NULL, NULL, NULL,
785     "ResetReq", "ResetAck",
786 };
787
788 int
789 ccp_printpkt(p, plen, printer, arg)
790     u_char *p;
791     int plen;
792     void (*printer) __P((void *, char *, ...));
793     void *arg;
794 {
795     u_char *p0, *optend;
796     int code, id, len;
797     int optlen;
798
799     p0 = p;
800     if (plen < HEADERLEN)
801         return 0;
802     code = p[0];
803     id = p[1];
804     len = (p[2] << 8) + p[3];
805     if (len < HEADERLEN || len > plen)
806         return 0;
807
808     if (code >= 1 && code <= sizeof(ccp_codenames) / sizeof(char *)
809         && ccp_codenames[code-1] != NULL)
810         printer(arg, " %s", ccp_codenames[code-1]);
811     else
812         printer(arg, " code=0x%x", code);
813     printer(arg, " id=0x%x", id);
814     len -= HEADERLEN;
815     p += HEADERLEN;
816
817     switch (code) {
818     case CONFREQ:
819     case CONFACK:
820     case CONFNAK:
821     case CONFREJ:
822         /* print list of possible compression methods */
823         while (len >= 2) {
824             code = p[0];
825             optlen = p[1];
826             if (optlen < 2 || optlen > len)
827                 break;
828             printer(arg, " <");
829             len -= optlen;
830             optend = p + optlen;
831             switch (code) {
832             case CI_DEFLATE:
833                 if (optlen >= CILEN_DEFLATE) {
834                     printer(arg, "deflate %d", DEFLATE_SIZE(p[2]));
835                     if (DEFLATE_METHOD(p[2]) != DEFLATE_METHOD_VAL)
836                         printer(arg, " method %d", DEFLATE_METHOD(p[2]));
837                     if (p[3] != DEFLATE_CHK_SEQUENCE)
838                         printer(arg, " check %d", p[3]);
839                     p += CILEN_DEFLATE;
840                 }
841                 break;
842             case CI_BSD_COMPRESS:
843                 if (optlen >= CILEN_BSD_COMPRESS) {
844                     printer(arg, "bsd v%d %d", BSD_VERSION(p[2]),
845                             BSD_NBITS(p[2]));
846                     p += CILEN_BSD_COMPRESS;
847                 }
848                 break;
849             case CI_PREDICTOR_1:
850                 if (optlen >= CILEN_PREDICTOR_1) {
851                     printer(arg, "predictor 1");
852                     p += CILEN_PREDICTOR_1;
853                 }
854                 break;
855             case CI_PREDICTOR_2:
856                 if (optlen >= CILEN_PREDICTOR_2) {
857                     printer(arg, "predictor 2");
858                     p += CILEN_PREDICTOR_2;
859                 }
860                 break;
861             }
862             while (p < optend)
863                 printer(arg, " %.2x", *p++);
864             printer(arg, ">");
865         }
866         break;
867     }
868
869     /* dump out the rest of the packet in hex */
870     while (--len >= 0)
871         printer(arg, " %.2x", *p++);
872
873     return p - p0;
874 }
875
876 /*
877  * We have received a packet that the decompressor failed to
878  * decompress.  Here we would expect to issue a reset-request, but
879  * Motorola has a patent on resetting the compressor as a result of
880  * detecting an error in the decompressed data after decompression.
881  * (See US patent 5,130,993; international patent publication number
882  * WO 91/10289; Australian patent 73296/91.)
883  *
884  * So we ask the kernel whether the error was detected after
885  * decompression; if it was, we take CCP down, thus disabling
886  * compression :-(, otherwise we issue the reset-request.
887  */
888 void
889 ccp_datainput(unit, pkt, len)
890     int unit;
891     u_char *pkt;
892     int len;
893 {
894     fsm *f;
895
896     f = &ccp_fsm[unit];
897     if (f->state == OPENED) {
898         if (ccp_fatal_error(unit)) {
899             /*
900              * Disable compression by taking CCP down.
901              */
902             syslog(LOG_ERR, "Lost compression sync: disabling compression");
903             ccp_close(unit);
904         } else {
905             /*
906              * Send a reset-request to reset the peer's compressor.
907              * We don't do that if we are still waiting for an
908              * acknowledgement to a previous reset-request.
909              */
910             if (!(ccp_localstate[f->unit] & RACK_PENDING)) {
911                 fsm_sdata(f, CCP_RESETREQ, f->reqid = ++f->id, NULL, 0);
912                 TIMEOUT(ccp_rack_timeout, (caddr_t) f, RACKTIMEOUT);
913                 ccp_localstate[f->unit] |= RACK_PENDING;
914             } else
915                 ccp_localstate[f->unit] |= RREQ_REPEAT;
916         }
917     }
918 }
919
920 /*
921  * Timeout waiting for reset-ack.
922  */
923 static void
924 ccp_rack_timeout(arg)
925     caddr_t arg;
926 {
927     fsm *f = (fsm *) arg;
928
929     if (f->state == OPENED && ccp_localstate[f->unit] & RREQ_REPEAT) {
930         fsm_sdata(f, CCP_RESETREQ, f->reqid, NULL, 0);
931         TIMEOUT(ccp_rack_timeout, (caddr_t) f, RACKTIMEOUT);
932         ccp_localstate[f->unit] &= ~RREQ_REPEAT;
933     } else
934         ccp_localstate[f->unit] &= ~RACK_PENDING;
935 }
936