xref: /illumos-gate/usr/src/cmd/cmd-inet/usr.bin/pppd/ccp.c (revision 45ede40b2394db7967e59f19288fae9b62efd4aa)
1 /*
2  * ccp.c - PPP Compression Control Protocol.
3  *
4  * Copyright (c) 2000 by Sun Microsystems, Inc.
5  * All rights reserved.
6  *
7  * Copyright (c) 1994 The Australian National University.
8  * All rights reserved.
9  *
10  * Permission to use, copy, modify, and distribute this software and its
11  * documentation is hereby granted, provided that the above copyright
12  * notice appears in all copies.  This software is provided without any
13  * warranty, express or implied. The Australian National University
14  * makes no representations about the suitability of this software for
15  * any purpose.
16  *
17  * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
18  * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
19  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
20  * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
21  * OF SUCH DAMAGE.
22  *
23  * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
24  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
25  * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
26  * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
27  * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
28  * OR MODIFICATIONS.
29  */
30 /*
31  * Copyright (c) 2016 by Delphix. All rights reserved.
32  */
33 
34 #include <stdlib.h>
35 #include <string.h>
36 
37 #include "pppd.h"
38 #include "fsm.h"
39 #include "ccp.h"
40 #include <net/ppp-comp.h>
41 
42 /*
43  * Command-line options.
44  */
45 static int setbsdcomp __P((char **, option_t *));
46 static int setdeflate __P((char **, option_t *));
47 
48 static option_t ccp_option_list[] = {
49     { "noccp", o_bool, &ccp_protent.enabled_flag,
50       "Disable CCP negotiation" },
51     { "-ccp", o_bool, &ccp_protent.enabled_flag,
52       "Disable CCP negotiation" },
53     { "bsdcomp", o_special, (void *)setbsdcomp,
54       "Request BSD-Compress packet compression" },
55     { "nobsdcomp", o_bool, &ccp_wantoptions[0].bsd_compress,
56       "don't allow BSD-Compress", OPT_A2COPY,
57       &ccp_allowoptions[0].bsd_compress },
58     { "-bsdcomp", o_bool, &ccp_wantoptions[0].bsd_compress,
59       "don't allow BSD-Compress", OPT_A2COPY,
60       &ccp_allowoptions[0].bsd_compress },
61     { "deflate", o_special, (void *)setdeflate,
62       "request Deflate compression" },
63     { "nodeflate", o_bool, &ccp_wantoptions[0].deflate,
64       "don't allow Deflate compression", OPT_A2COPY,
65       &ccp_allowoptions[0].deflate },
66     { "-deflate", o_bool, &ccp_wantoptions[0].deflate,
67       "don't allow Deflate compression", OPT_A2COPY,
68       &ccp_allowoptions[0].deflate },
69     { "nodeflatedraft", o_bool, &ccp_wantoptions[0].deflate_draft,
70       "don't use draft deflate #", OPT_A2COPY,
71       &ccp_allowoptions[0].deflate_draft },
72     { "predictor1", o_bool, &ccp_wantoptions[0].predictor_1,
73       "request Predictor-1", 1, &ccp_allowoptions[0].predictor_1 },
74     { "nopredictor1", o_bool, &ccp_wantoptions[0].predictor_1,
75       "don't allow Predictor-1", OPT_A2COPY,
76       &ccp_allowoptions[0].predictor_1 },
77     { "-predictor1", o_bool, &ccp_wantoptions[0].predictor_1,
78       "don't allow Predictor-1", OPT_A2COPY,
79       &ccp_allowoptions[0].predictor_1 },
80 
81     { NULL }
82 };
83 
84 /*
85  * Protocol entry points from main code.
86  */
87 static void ccp_init __P((int unit));
88 static void ccp_open __P((int unit));
89 static void ccp_close __P((int unit, char *));
90 static void ccp_lowerup __P((int unit));
91 static void ccp_lowerdown __P((int));
92 static void ccp_input __P((int unit, u_char *pkt, int len));
93 static void ccp_protrej __P((int unit));
94 static int  ccp_printpkt __P((u_char *pkt, int len,
95 			      void (*printer) __P((void *, const char *, ...)),
96 			      void *arg));
97 static void ccp_datainput __P((int unit, u_char *pkt, int len));
98 
99 struct protent ccp_protent = {
100     PPP_CCP,
101     ccp_init,
102     ccp_input,
103     ccp_protrej,
104     ccp_lowerup,
105     ccp_lowerdown,
106     ccp_open,
107     ccp_close,
108     ccp_printpkt,
109     ccp_datainput,
110     1,
111     "CCP",
112     "Compressed",
113     ccp_option_list,
114     NULL,
115     NULL,
116     NULL
117 };
118 
119 fsm ccp_fsm[NUM_PPP];
120 ccp_options ccp_wantoptions[NUM_PPP];	/* what to request the peer to use */
121 ccp_options ccp_gotoptions[NUM_PPP];	/* what the peer agreed to do */
122 ccp_options ccp_allowoptions[NUM_PPP];	/* what we'll agree to do */
123 ccp_options ccp_hisoptions[NUM_PPP];	/* what we agreed to do */
124 
125 /*
126  * Callbacks for fsm code.
127  */
128 static void ccp_resetci __P((fsm *));
129 static int  ccp_cilen __P((fsm *));
130 static void ccp_addci __P((fsm *, u_char *, int *));
131 static int  ccp_ackci __P((fsm *, u_char *, int));
132 static int  ccp_nakci __P((fsm *, u_char *, int));
133 static int  ccp_rejci __P((fsm *, u_char *, int));
134 static int  ccp_reqci __P((fsm *, u_char *, int *, int));
135 static void ccp_up __P((fsm *));
136 static void ccp_down __P((fsm *));
137 static int  ccp_extcode __P((fsm *, int, int, u_char *, int));
138 static int  ccp_codereject __P((fsm *p, int code, int id, u_char *inp,
139     int len));
140 
141 static fsm_callbacks ccp_callbacks = {
142     ccp_resetci,		/* Reset our Configuration Information */
143     ccp_cilen,                  /* Length of our Configuration Information */
144     ccp_addci,                  /* Add our Configuration Information */
145     ccp_ackci,                  /* ACK our Configuration Information */
146     ccp_nakci,                  /* NAK our Configuration Information */
147     ccp_rejci,                  /* Reject our Configuration Information */
148     ccp_reqci,                  /* Request peer's Configuration Information */
149     ccp_up,                     /* Called when fsm reaches OPENED state */
150     ccp_down,                   /* Called when fsm leaves OPENED state */
151     NULL,                       /* Called when we want the lower layer up */
152     NULL,                       /* Called when we want the lower layer down */
153     NULL,			/* Retransmission is necessary */
154     ccp_extcode,                /* Called to handle LCP-specific codes */
155     "CCP",			/* String name of protocol */
156     ccp_codereject,             /* Peer rejected a code number */
157 };
158 
159 /*
160  * Local statics.
161  */
162 static void ccp_rack_timeout __P((void *));
163 static char * method_name __P((ccp_options *, ccp_options *));
164 
165 /*
166  * Do we want / did we get any compression?
167  */
168 #define ANY_COMPRESS(opt)	((opt).deflate || (opt).bsd_compress \
169 				 || (opt).predictor_1 || (opt).predictor_2)
170 
171 /*
172  * Local state (mainly for handling reset-reqs and reset-acks).
173  */
174 static int ccp_localstate[NUM_PPP];
175 #define RACK_PENDING	0x0001	/* waiting for reset-ack */
176 #define RREQ_REPEAT	0x0002	/* send another reset-req if no reset-ack */
177 #define RREQ_REJECTED	0x0004	/* peer code-rejected reset-request */
178 #define RACK_REJECTED	0x0008	/* peer code-rejected reset-ack */
179 #define RREQ_IGNORED	0x0010	/* peer just ignored reset-request */
180 
181 #define RACKTIMEOUT	1	/* time in seconds between Reset-Requests */
182 
183 static int all_rejected[NUM_PPP];	/* we rejected all peer's options */
184 
185 #ifdef COMP_TUNE
186 static int deflate_tune = -1;	/* compression effort level for deflate */
187 #endif
188 static int deflate_rmax = DEFLATE_MAX_SIZE;	/* max rbits */
189 static int deflate_amax = DEFLATE_MAX_SIZE;	/* max abits */
190 
191 /*
192  * Option parsing.
193  */
194 /*ARGSUSED*/
195 static int
196 setbsdcomp(argv, opt)
197     char **argv;
198     option_t *opt;
199 {
200     int rbits, abits;
201     char *str, *endp;
202 
203     str = *argv;
204     abits = rbits = strtol(str, &endp, 0);
205     if (endp != str && *endp == ',') {
206 	str = endp + 1;
207 	abits = strtol(str, &endp, 0);
208     }
209     if (*endp != '\0' || endp == str) {
210 	option_error("invalid parameter '%s' for bsdcomp option", *argv);
211 	return 0;
212     }
213     if ((rbits != 0 && (rbits < BSD_MIN_BITS || rbits > BSD_MAX_BITS))
214 	|| (abits != 0 && (abits < BSD_MIN_BITS || abits > BSD_MAX_BITS))) {
215 	option_error("bsdcomp option values must be 0 or %d .. %d",
216 		     BSD_MIN_BITS, BSD_MAX_BITS);
217 	return 0;
218     }
219     if (rbits > 0) {
220 	ccp_wantoptions[0].bsd_compress = 1;
221 	ccp_wantoptions[0].bsd_bits = rbits;
222     } else
223 	ccp_wantoptions[0].bsd_compress = 0;
224     if (abits > 0) {
225 	ccp_allowoptions[0].bsd_compress = 1;
226 	ccp_allowoptions[0].bsd_bits = abits;
227     } else
228 	ccp_allowoptions[0].bsd_compress = 0;
229     return 1;
230 }
231 
232 /*ARGSUSED*/
233 static int
234 setdeflate(argv, opt)
235     char **argv;
236     option_t *opt;
237 {
238     int rbits, abits, def_rmax, def_amax;
239     char *str, *endp;
240 
241     str = endp = *argv;
242     if (*str == ',')
243 	abits = rbits = -1;
244     else
245 	abits = rbits = strtol(str, &endp, 0);
246     if (*endp == ',') {
247 	str = ++endp;
248 	if (*str == ',')
249 	    abits = rbits;
250 	else
251 	    abits = strtol(str, &endp, 0);
252     }
253 #ifdef COMP_TUNE
254     if (*endp == ',' && privileged_option) {
255 	str = ++endp;
256 	deflate_tune = strtol(str, &endp, 0);
257     }
258 #endif
259     if (*endp != '\0' || endp == str) {
260 	option_error("invalid parameter '%s' for deflate option", *argv);
261 	return 0;
262     }
263     if (privileged_option) {
264 	def_rmax = def_amax = DEFLATE_MAX_SIZE;
265     } else {
266 	def_rmax = deflate_rmax;
267 	def_amax = deflate_amax;
268     }
269     if (rbits < 0)
270 	rbits = def_rmax;
271     if (abits < 0)
272 	abits = def_amax;
273     if ((rbits != 0 && (rbits <= DEFLATE_MIN_SIZE || rbits > def_rmax))
274 	|| (abits != 0 && (abits <= DEFLATE_MIN_SIZE || abits > def_amax))) {
275 	option_error("deflate option values must be 0 or {%d,%d} .. {%d,%d}",
276 		     DEFLATE_MIN_SIZE+1, DEFLATE_MIN_SIZE+1,
277 		     def_rmax, def_amax);
278 	return 0;
279     }
280     if (privileged_option) {
281 	deflate_rmax = rbits;
282 	deflate_amax = abits;
283     }
284     if (rbits > 0) {
285 	ccp_wantoptions[0].deflate = 1;
286 	ccp_wantoptions[0].deflate_size = rbits;
287     } else
288 	ccp_wantoptions[0].deflate = 0;
289     if (abits > 0) {
290 	ccp_allowoptions[0].deflate = 1;
291 	ccp_allowoptions[0].deflate_size = abits;
292     } else
293 	ccp_allowoptions[0].deflate = 0;
294     return 1;
295 }
296 
297 
298 /*
299  * ccp_init - initialize CCP.
300  */
301 static void
302 ccp_init(unit)
303     int unit;
304 {
305     fsm *f = &ccp_fsm[unit];
306 
307     f->unit = unit;
308     f->protocol = PPP_CCP;
309     f->callbacks = &ccp_callbacks;
310     fsm_init(f);
311     f->flags |= OPT_RESTART;
312 
313     BZERO(&ccp_wantoptions[unit],  sizeof(ccp_options));
314     BZERO(&ccp_gotoptions[unit],   sizeof(ccp_options));
315     BZERO(&ccp_allowoptions[unit], sizeof(ccp_options));
316     BZERO(&ccp_hisoptions[unit],   sizeof(ccp_options));
317 
318     ccp_wantoptions[0].deflate = 1;
319     ccp_wantoptions[0].deflate_size = DEFLATE_MAX_SIZE;
320     ccp_wantoptions[0].deflate_correct = 1;
321     ccp_wantoptions[0].deflate_draft = 1;
322     ccp_allowoptions[0].deflate = 1;
323     ccp_allowoptions[0].deflate_size = DEFLATE_MAX_SIZE;
324     ccp_allowoptions[0].deflate_correct = 1;
325     ccp_allowoptions[0].deflate_draft = 1;
326 
327     ccp_wantoptions[0].bsd_compress = 1;
328     ccp_wantoptions[0].bsd_bits = BSD_MAX_BITS;
329     ccp_allowoptions[0].bsd_compress = 1;
330     ccp_allowoptions[0].bsd_bits = BSD_MAX_BITS;
331 
332     ccp_allowoptions[0].predictor_1 = 1;
333 }
334 
335 /*
336  * ccp_open - CCP is allowed to come up.
337  */
338 static void
339 ccp_open(unit)
340     int unit;
341 {
342     fsm *f = &ccp_fsm[unit];
343 
344     /*
345      * If we haven't gone open yet (first time through), then go open
346      * but not up.  Otherwise, skip this to allow reopen to reset the
347      * compressor.
348      */
349     if (f->state != OPENED)
350 	ccp_flags_set(unit, 1, 0);
351 
352     /*
353      * Find out which compressors the kernel supports before
354      * deciding whether to open in silent mode.
355      */
356     ccp_resetci(f);
357     if (!ANY_COMPRESS(ccp_gotoptions[unit]))
358 	f->flags |= OPT_SILENT;
359 
360     fsm_open(f);
361 }
362 
363 /*
364  * ccp_close - Terminate CCP.
365  */
366 static void
367 ccp_close(unit, reason)
368     int unit;
369     char *reason;
370 {
371     ccp_flags_set(unit, 0, 0);
372     fsm_close(&ccp_fsm[unit], reason);
373 }
374 
375 /*
376  * ccp_lowerup - we may now transmit CCP packets.
377  */
378 static void
379 ccp_lowerup(unit)
380     int unit;
381 {
382     fsm_lowerup(&ccp_fsm[unit]);
383 }
384 
385 /*
386  * ccp_lowerdown - we may not transmit CCP packets.
387  */
388 static void
389 ccp_lowerdown(unit)
390     int unit;
391 {
392     fsm_lowerdown(&ccp_fsm[unit]);
393 }
394 
395 /*
396  * ccp_input - process a received CCP packet.
397  */
398 static void
399 ccp_input(unit, p, len)
400     int unit;
401     u_char *p;
402     int len;
403 {
404     fsm *f = &ccp_fsm[unit];
405     int oldstate;
406 
407     /*
408      * Check for a terminate-request so we can print a message.
409      */
410     oldstate = f->state;
411     fsm_input(f, p, len);
412     if (oldstate == OPENED && p[0] == CODE_TERMREQ && f->state != OPENED)
413 	notice("Compression disabled by peer.");
414 
415     /*
416      * If we get a terminate-ack and we're not asking for compression,
417      * close CCP.  (Terminate-Request is handled by fsm_input() above.)
418      */
419     if (oldstate == REQSENT && p[0] == CODE_TERMACK
420 	&& !ANY_COMPRESS(ccp_gotoptions[unit]))
421 	ccp_close(unit, "No compression negotiated");
422 }
423 
424 /*
425  * Handle a CCP-specific code.
426  */
427 static int
428 ccp_extcode(f, code, id, p, len)
429     fsm *f;
430     int code, id;
431     u_char *p;
432     int len;
433 {
434     switch (code) {
435     case CCP_RESETREQ:
436 	/* If not open, then silently ignore. */
437 	if (f->state != OPENED)
438 	    break;
439 	/* send a reset-ack, which our transmitter module will see and
440 	   reset its compression state. */
441 	fsm_sdata(f, CCP_RESETACK, id, p, len);
442 	break;
443 
444     case CCP_RESETACK:
445 	/*
446 	 * Note that the compression module isn't picky about ID
447 	 * numbers and such.
448 	 */
449 	ccp_localstate[f->unit] &= ~RREQ_IGNORED & ~RREQ_REJECTED;
450 	if ((ccp_localstate[f->unit] & RACK_PENDING) && id == f->reqid) {
451 	    ccp_localstate[f->unit] &= ~RACK_PENDING & ~RREQ_REPEAT;
452 	    UNTIMEOUT(ccp_rack_timeout, f);
453 	}
454 	break;
455 
456     default:
457 	/* Tell fsm to send code reject */
458 	return (0);
459     }
460 
461     return (1);
462 }
463 
464 /*
465  * Handle Code-Reject for one of our extended codes by dropping back to
466  * reopen as mechanism to restart compression.
467  */
468 /*ARGSUSED*/
469 static int
470 ccp_codereject(f, code, id, inp, len)
471     fsm *f;
472     int code, id;
473     u_char *inp;
474     int len;
475 {
476     switch (code) {
477     case CCP_RESETREQ:
478 	if (!(ccp_localstate[f->unit] & RREQ_REJECTED)) {
479 	    info("peer has rejected CCP Reset-Request; falling back on Open");
480 	    if (f->state == OPENED)
481 		ccp_open(f->unit);
482 	}
483 	ccp_localstate[f->unit] |= RREQ_REJECTED;
484 	return (0);
485 
486     case CCP_RESETACK:
487 	/*
488 	 * Peer must have sent us CCP Reset-Request but then code-rejected when
489 	 * we sent CCP Reset-Ack.  It seems to have changed its mind, and we
490 	 * have to obey its wishes.
491 	 */
492 	ccp_localstate[f->unit] |= RACK_REJECTED;
493 	notice("peer has erroneously rejected CCP Reset-Ack");
494 	f->term_reason = "peer sent Code-Reject for CCP Reset-Ack";
495 	f->term_reason_len = strlen(f->term_reason);
496 	break;
497 
498     default:
499 	f->term_reason = "peer sent invalid Code-Reject";
500 	break;
501     }
502 
503     f->term_reason_len = strlen(f->term_reason);
504     return (1);
505 }
506 
507 /*
508  * ccp_protrej - peer doesn't talk CCP.
509  */
510 static void
511 ccp_protrej(unit)
512     int unit;
513 {
514     /* Neither open nor up. */
515     ccp_flags_set(unit, 0, 0);
516     fsm_lowerdown(&ccp_fsm[unit]);
517 }
518 
519 /*
520  * ccp_resetci - initialize at start of negotiation.
521  */
522 static void
523 ccp_resetci(f)
524     fsm *f;
525 {
526     ccp_options *go = &ccp_gotoptions[f->unit];
527     u_char opt_buf[16];
528 
529     *go = ccp_wantoptions[f->unit];
530     all_rejected[f->unit] = 0;
531 
532     /*
533      * Check whether the kernel knows about the various
534      * decompression methods we might request.
535      */
536     if (go->bsd_compress) {
537 	opt_buf[0] = CI_BSD_COMPRESS;
538 	opt_buf[1] = CILEN_BSD_COMPRESS;
539 	opt_buf[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, BSD_MIN_BITS);
540 	if (ccp_test(f->unit, opt_buf, CILEN_BSD_COMPRESS, 0) <= 0)
541 	    go->bsd_compress = 0;
542     }
543     if (go->deflate) {
544 	if (go->deflate_correct) {
545 	    opt_buf[0] = CI_DEFLATE;
546 	    opt_buf[1] = CILEN_DEFLATE;
547 	    opt_buf[2] = DEFLATE_MAKE_OPT(DEFLATE_MIN_SIZE+1);
548 	    opt_buf[3] = DEFLATE_CHK_SEQUENCE;
549 	    if (ccp_test(f->unit, opt_buf, CILEN_DEFLATE, 0) <= 0)
550 		go->deflate_correct = 0;
551 	}
552 	if (go->deflate_draft) {
553 	    opt_buf[0] = CI_DEFLATE_DRAFT;
554 	    opt_buf[1] = CILEN_DEFLATE;
555 	    opt_buf[2] = DEFLATE_MAKE_OPT(DEFLATE_MIN_SIZE+1);
556 	    opt_buf[3] = DEFLATE_CHK_SEQUENCE;
557 	    if (ccp_test(f->unit, opt_buf, CILEN_DEFLATE, 0) <= 0)
558 		go->deflate_draft = 0;
559 	}
560 	if (!go->deflate_correct && !go->deflate_draft)
561 	    go->deflate = 0;
562     }
563     if (go->predictor_1) {
564 	opt_buf[0] = CI_PREDICTOR_1;
565 	opt_buf[1] = CILEN_PREDICTOR_1;
566 	if (ccp_test(f->unit, opt_buf, CILEN_PREDICTOR_1, 0) <= 0)
567 	    go->predictor_1 = 0;
568     }
569     if (go->predictor_2) {
570 	opt_buf[0] = CI_PREDICTOR_2;
571 	opt_buf[1] = CILEN_PREDICTOR_2;
572 	if (ccp_test(f->unit, opt_buf, CILEN_PREDICTOR_2, 0) <= 0)
573 	    go->predictor_2 = 0;
574     }
575 }
576 
577 /*
578  * ccp_cilen - Return total length of our configuration info.
579  */
580 static int
581 ccp_cilen(f)
582     fsm *f;
583 {
584     ccp_options *go = &ccp_gotoptions[f->unit];
585 
586     return (go->bsd_compress? CILEN_BSD_COMPRESS: 0)
587 	+ (go->deflate && go->deflate_correct ? CILEN_DEFLATE : 0)
588 	+ (go->deflate && go->deflate_draft ? CILEN_DEFLATE : 0)
589 	+ (go->predictor_1? CILEN_PREDICTOR_1: 0)
590 	+ (go->predictor_2? CILEN_PREDICTOR_2: 0);
591 }
592 
593 /*
594  * ccp_addci - put our requests in a packet.
595  */
596 static void
597 ccp_addci(f, p, lenp)
598     fsm *f;
599     u_char *p;
600     int *lenp;
601 {
602     int res;
603     ccp_options *go = &ccp_gotoptions[f->unit];
604     u_char *p0 = p;
605 
606     /*
607      * Add the compression types that we can receive, in decreasing
608      * preference order.  Get the kernel to allocate the first one
609      * in case it gets Acked.
610      */
611     if (go->deflate) {
612 	p[0] = go->deflate_correct? CI_DEFLATE: CI_DEFLATE_DRAFT;
613 	p[1] = CILEN_DEFLATE;
614 	p[2] = DEFLATE_MAKE_OPT(go->deflate_size);
615 	p[3] = DEFLATE_CHK_SEQUENCE;
616 	for (;;) {
617 	    res = ccp_test(f->unit, p, CILEN_DEFLATE, 0);
618 	    if (res > 0) {
619 		p += CILEN_DEFLATE;
620 		break;
621 	    }
622 	    if (res < 0 || go->deflate_size <= DEFLATE_MIN_SIZE+1) {
623 		go->deflate = 0;
624 		break;
625 	    }
626 	    --go->deflate_size;
627 	    p[2] = DEFLATE_MAKE_OPT(go->deflate_size);
628 	}
629 	/* If we're offering both, then this is second. */
630 	if (p != p0 && go->deflate_correct && go->deflate_draft) {
631 	    p[0] = CI_DEFLATE_DRAFT;
632 	    p[1] = CILEN_DEFLATE;
633 	    p[2] = p[2 - CILEN_DEFLATE];
634 	    p[3] = DEFLATE_CHK_SEQUENCE;
635 	    p += CILEN_DEFLATE;
636 	}
637     }
638     if (go->bsd_compress) {
639 	p[0] = CI_BSD_COMPRESS;
640 	p[1] = CILEN_BSD_COMPRESS;
641 	p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits);
642 	if (p != p0) {
643 	    p += CILEN_BSD_COMPRESS;	/* not the first option */
644 	} else {
645 	    for (;;) {
646 		res = ccp_test(f->unit, p, CILEN_BSD_COMPRESS, 0);
647 		if (res > 0) {
648 		    p += CILEN_BSD_COMPRESS;
649 		    break;
650 		}
651 		if (res < 0 || go->bsd_bits <= BSD_MIN_BITS) {
652 		    go->bsd_compress = 0;
653 		    break;
654 		}
655 		--go->bsd_bits;
656 		p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits);
657 	    }
658 	}
659     }
660     /*
661      * Prefer Predictor-1 over Predictor-2.  (The latter requires the use
662      * of LAP-B and has no known implementations.)
663      */
664     if (go->predictor_1) {
665 	p[0] = CI_PREDICTOR_1;
666 	p[1] = CILEN_PREDICTOR_1;
667 	if (p == p0 && ccp_test(f->unit, p, CILEN_PREDICTOR_1, 0) <= 0) {
668 	    go->predictor_1 = 0;
669 	} else {
670 	    p += CILEN_PREDICTOR_1;
671 	}
672     }
673     if (go->predictor_2) {
674 	p[0] = CI_PREDICTOR_2;
675 	p[1] = CILEN_PREDICTOR_2;
676 	if (p == p0 && ccp_test(f->unit, p, CILEN_PREDICTOR_2, 0) <= 0) {
677 	    go->predictor_2 = 0;
678 	} else {
679 	    p += CILEN_PREDICTOR_2;
680 	}
681     }
682 
683     go->method = (p > p0)? p0[0]: -1;
684 
685     *lenp = p - p0;
686 }
687 
688 /*
689  * ccp_ackci - process a received configure-ack, and return
690  * 1 iff the packet was OK.
691  */
692 static int
693 ccp_ackci(f, p, len)
694     fsm *f;
695     u_char *p;
696     int len;
697 {
698     ccp_options *go = &ccp_gotoptions[f->unit];
699     u_char *p0 = p;
700 
701     if (go->deflate && go->deflate_correct) {
702 	if (len < CILEN_DEFLATE
703 	    || p[0] != CI_DEFLATE || p[1] != CILEN_DEFLATE
704 	    || p[2] != DEFLATE_MAKE_OPT(go->deflate_size)
705 	    || p[3] != DEFLATE_CHK_SEQUENCE)
706 	    return 0;
707 	/* Cope with non-standard first/fast ack */
708 	if (p == p0 && len == 0)
709 	    return 1;
710 	p += CILEN_DEFLATE;
711 	len -= CILEN_DEFLATE;
712     }
713     if (go->deflate && go->deflate_draft) {
714 	if (len < CILEN_DEFLATE
715 	    || p[0] != CI_DEFLATE_DRAFT || p[1] != CILEN_DEFLATE
716 	    || p[2] != DEFLATE_MAKE_OPT(go->deflate_size)
717 	    || p[3] != DEFLATE_CHK_SEQUENCE)
718 	    return 0;
719 	/* Cope with non-standard first/fast ack */
720 	if (p == p0 && len == 0)
721 	    return 1;
722 	p += CILEN_DEFLATE;
723 	len -= CILEN_DEFLATE;
724     }
725     if (go->bsd_compress) {
726 	if (len < CILEN_BSD_COMPRESS
727 	    || p[0] != CI_BSD_COMPRESS || p[1] != CILEN_BSD_COMPRESS
728 	    || p[2] != BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits))
729 	    return 0;
730 	/* Cope with non-standard first/fast ack */
731 	if (p == p0 && len == 0)
732 	    return 1;
733 	p += CILEN_BSD_COMPRESS;
734 	len -= CILEN_BSD_COMPRESS;
735     }
736     if (go->predictor_1) {
737 	if (len < CILEN_PREDICTOR_1
738 	    || p[0] != CI_PREDICTOR_1 || p[1] != CILEN_PREDICTOR_1)
739 	    return 0;
740 	/* Cope with non-standard first/fast ack */
741 	if (p == p0 && len == 0)
742 	    return 1;
743 	p += CILEN_PREDICTOR_1;
744 	len -= CILEN_PREDICTOR_1;
745     }
746     if (go->predictor_2) {
747 	if (len < CILEN_PREDICTOR_2
748 	    || p[0] != CI_PREDICTOR_2 || p[1] != CILEN_PREDICTOR_2)
749 	    return 0;
750 	/* Cope with non-standard first/fast ack */
751 	if (p == p0 && len == 0)
752 	    return 1;
753 	p += CILEN_PREDICTOR_2;
754 	len -= CILEN_PREDICTOR_2;
755     }
756 
757     /* Peer cannot ack something that wasn't sent. */
758     if (len != 0)
759 	return 0;
760     return 1;
761 }
762 
763 /*
764  * ccp_nakci - process received configure-nak.
765  * Returns 1 iff the nak was OK.
766  */
767 static int
768 ccp_nakci(f, p, len)
769     fsm *f;
770     u_char *p;
771     int len;
772 {
773     ccp_options *go = &ccp_gotoptions[f->unit];
774     ccp_options no;		/* options we've seen already */
775     ccp_options try;		/* options to ask for next time */
776 
777     BZERO(&no, sizeof(no));
778     try = *go;
779 
780     if (go->deflate && go->deflate_correct && len >= CILEN_DEFLATE &&
781 	p[0] == CI_DEFLATE) {
782 	no.deflate = 1;
783 	/*
784 	 * Peer wants us to use a different code size or something.
785 	 * Stop asking for Deflate if we don't understand its suggestion.
786 	 */
787 	if (p[1] != CILEN_DEFLATE
788 	    || DEFLATE_METHOD(p[2]) != DEFLATE_METHOD_VAL
789 	    || DEFLATE_SIZE(p[2]) <= DEFLATE_MIN_SIZE
790 	    || p[3] != DEFLATE_CHK_SEQUENCE)
791 	    try.deflate_correct = 0;
792 	else if (DEFLATE_SIZE(p[2]) < go->deflate_size)
793 	    try.deflate_size = DEFLATE_SIZE(p[2]);
794 	len -= p[1];
795 	p += p[1];
796     }
797 
798     if (go->deflate && go->deflate_draft && len >= CILEN_DEFLATE &&
799 	p[0] == CI_DEFLATE_DRAFT) {
800 	no.deflate = 1;
801 	/*
802 	 * Peer wants us to use a different code size or something.
803 	 * Stop asking for Deflate using the old algorithm number if
804 	 * we don't understand its suggestion.  (Note that this will
805 	 * happen if the peer is running Magnalink instead of
806 	 * old-style Deflate.)
807 	 */
808 	if (p[1] != CILEN_DEFLATE
809 	    || DEFLATE_METHOD(p[2]) != DEFLATE_METHOD_VAL
810 	    || DEFLATE_SIZE(p[2]) <= DEFLATE_MIN_SIZE
811 	    || p[3] != DEFLATE_CHK_SEQUENCE)
812 	    try.deflate_draft = 0;
813 	else if (DEFLATE_SIZE(p[2]) < go->deflate_size)
814 	    try.deflate_size = DEFLATE_SIZE(p[2]);
815 	len -= p[1];
816 	p += p[1];
817     }
818 
819     if (!try.deflate_correct && !try.deflate_draft)
820 	try.deflate = 0;
821 
822     if (go->bsd_compress && len >= CILEN_BSD_COMPRESS &&
823 	p[0] == CI_BSD_COMPRESS) {
824 	no.bsd_compress = 1;
825 	/*
826 	 * Peer wants us to use a different number of bits
827 	 * or a different version.
828 	 */
829 	if (p[1] != CILEN_BSD_COMPRESS ||
830 	    BSD_VERSION(p[2]) != BSD_CURRENT_VERSION)
831 	    try.bsd_compress = 0;
832 	else if (BSD_NBITS(p[2]) < go->bsd_bits)
833 	    try.bsd_bits = BSD_NBITS(p[2]);
834 	len -= p[1];
835 	p += p[1];
836     }
837 
838     /*
839      * Predictor-1 and 2 have no options, so they can't be Naked.
840      *
841      * There may be remaining options but we ignore them.
842      */
843 
844     if (f->state != OPENED)
845 	*go = try;
846     return 1;
847 }
848 
849 /*
850  * ccp_rejci - peer rejects some of our suggested compression methods.
851  */
852 static int
853 ccp_rejci(f, p, len)
854     fsm *f;
855     u_char *p;
856     int len;
857 {
858     ccp_options *go = &ccp_gotoptions[f->unit];
859     ccp_options try;		/* options to request next time */
860 
861     try = *go;
862 
863     /*
864      * Cope with empty configure-rejects by ceasing to send
865      * configure-requests.
866      */
867     if (len == 0 && all_rejected[f->unit])
868 	return -1;
869 
870     if (go->deflate && go->deflate_correct && len >= CILEN_DEFLATE &&
871 	p[0] == CI_DEFLATE && p[1] == CILEN_DEFLATE) {
872 	if (p[2] != DEFLATE_MAKE_OPT(go->deflate_size)
873 	    || p[3] != DEFLATE_CHK_SEQUENCE)
874 	    return 0;		/* Rej is bad */
875 	try.deflate_correct = 0;
876 	p += CILEN_DEFLATE;
877 	len -= CILEN_DEFLATE;
878     }
879     if (go->deflate && go->deflate_draft && len >= CILEN_DEFLATE &&
880 	p[0] == CI_DEFLATE_DRAFT && p[1] == CILEN_DEFLATE) {
881 	if (p[2] != DEFLATE_MAKE_OPT(go->deflate_size)
882 	    || p[3] != DEFLATE_CHK_SEQUENCE)
883 	    return 0;		/* Rej is bad */
884 	try.deflate_draft = 0;
885 	p += CILEN_DEFLATE;
886 	len -= CILEN_DEFLATE;
887     }
888     if (!try.deflate_correct && !try.deflate_draft)
889 	try.deflate = 0;
890     if (go->bsd_compress && len >= CILEN_BSD_COMPRESS
891 	&& p[0] == CI_BSD_COMPRESS && p[1] == CILEN_BSD_COMPRESS) {
892 	if (p[2] != BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits))
893 	    return 0;
894 	try.bsd_compress = 0;
895 	p += CILEN_BSD_COMPRESS;
896 	len -= CILEN_BSD_COMPRESS;
897     }
898     if (go->predictor_1 && len >= CILEN_PREDICTOR_1
899 	&& p[0] == CI_PREDICTOR_1 && p[1] == CILEN_PREDICTOR_1) {
900 	try.predictor_1 = 0;
901 	p += CILEN_PREDICTOR_1;
902 	len -= CILEN_PREDICTOR_1;
903     }
904     if (go->predictor_2 && len >= CILEN_PREDICTOR_2
905 	&& p[0] == CI_PREDICTOR_2 && p[1] == CILEN_PREDICTOR_2) {
906 	try.predictor_2 = 0;
907 	p += CILEN_PREDICTOR_2;
908 	len -= CILEN_PREDICTOR_2;
909     }
910 
911     if (len != 0)
912 	return 0;
913 
914     if (f->state != OPENED)
915 	*go = try;
916 
917     return 1;
918 }
919 
920 /*
921  * ccp_reqci - process a received configure-request.
922  *
923  * Returns CODE_CONFACK, CODE_CONFNAK or CODE_CONFREJ and the packet
924  * is modified appropriately.
925  */
926 static int
927 ccp_reqci(f, p, lenp, dont_nak)
928     fsm *f;
929     u_char *p;
930     int *lenp;
931     int dont_nak;
932 {
933     int ret, newret, res;
934     u_char *p0, *nakp, *rejp, *pv;
935     int len, clen, type, nb;
936     ccp_options *ho = &ccp_hisoptions[f->unit];
937     ccp_options *ao = &ccp_allowoptions[f->unit];
938 
939     ret = CODE_CONFACK;
940     rejp = p0 = p;
941     nakp = nak_buffer;
942     len = *lenp;
943 
944     BZERO(ho, sizeof(ccp_options));
945     ho->method = (len > 0)? p[0]: -1;
946 
947     for (; len > 0; len -= clen, p += clen) {
948 	newret = CODE_CONFACK;
949 	if (len < 2 || p[1] > len) {
950 	    /*
951 	     * RFC 1661 page 40 -- if the option extends beyond the
952 	     * packet, then discard the entire packet.
953 	     */
954 	    return (0);
955 	}
956 
957 	type = p[0];
958 	clen = p[1];
959 
960 	pv = p;
961 	switch (type) {
962 	case CI_DEFLATE:
963 	case CI_DEFLATE_DRAFT:
964 	    if (!ao->deflate ||
965 		(!ao->deflate_correct && type == CI_DEFLATE) ||
966 		(!ao->deflate_draft && type == CI_DEFLATE_DRAFT)) {
967 		newret = CODE_CONFREJ;
968 		break;
969 	    }
970 
971 	    ho->deflate = 1;
972 	    nb = clen < CILEN_DEFLATE ? ao->deflate_size : DEFLATE_SIZE(p[2]);
973 	    ho->deflate_size = nb;
974 	    if (clen != CILEN_DEFLATE ||
975 		DEFLATE_METHOD(p[2]) != DEFLATE_METHOD_VAL ||
976 		p[3] != DEFLATE_CHK_SEQUENCE || nb > ao->deflate_size ||
977 		nb <= DEFLATE_MIN_SIZE) {
978 		newret = CODE_CONFNAK;
979 		if (dont_nak)
980 		    break;
981 		if (nb > ao->deflate_size)
982 		    nb = ao->deflate_size;
983 		else if (nb <= DEFLATE_MIN_SIZE)
984 		    nb = DEFLATE_MIN_SIZE+1;
985 		pv = nakp;
986 		PUTCHAR(type, nakp);
987 		PUTCHAR(CILEN_DEFLATE, nakp);
988 		PUTCHAR(DEFLATE_MAKE_OPT(nb), nakp);
989 		PUTCHAR(DEFLATE_CHK_SEQUENCE, nakp);
990 	    }
991 
992 	    /*
993 	     * Check whether we can do Deflate with the window
994 	     * size they want.  If the window is too big, reduce
995 	     * it until the kernel can cope and nak with that.
996 	     * We only check this for the first option.
997 	     */
998 	    if (p == p0) {
999 		for (;;) {
1000 		    res = ccp_test(f->unit, pv, CILEN_DEFLATE, 1);
1001 		    if (res > 0)
1002 			break;		/* it's OK now */
1003 		    if (res < 0 || nb <= DEFLATE_MIN_SIZE+1 || dont_nak) {
1004 			newret = CODE_CONFREJ;
1005 			break;
1006 		    }
1007 		    if (newret == CODE_CONFACK) {
1008 			BCOPY(pv, nakp, CILEN_DEFLATE);
1009 			pv = nakp;
1010 			nakp += CILEN_DEFLATE;
1011 			newret = CODE_CONFNAK;
1012 		    }
1013 		    --nb;
1014 		    pv[2] = DEFLATE_MAKE_OPT(nb);
1015 		}
1016 #ifdef COMP_TUNE
1017 		/* Tune Deflate compression effort. */
1018 		if (newret == CODE_CONFACK)
1019 		    ccp_tune(f->unit, deflate_tune);
1020 #endif
1021 	    }
1022 	    break;
1023 
1024 	case CI_BSD_COMPRESS:
1025 	    if (!ao->bsd_compress) {
1026 		newret = CODE_CONFREJ;
1027 		break;
1028 	    }
1029 
1030 	    ho->bsd_compress = 1;
1031 	    nb = clen < CILEN_BSD_COMPRESS ? ao->bsd_bits : BSD_NBITS(p[2]);
1032 	    ho->bsd_bits = nb;
1033 	    if (clen != CILEN_BSD_COMPRESS ||
1034 		BSD_VERSION(p[2]) != BSD_CURRENT_VERSION ||
1035 		nb > ao->bsd_bits || nb < BSD_MIN_BITS) {
1036 		newret = CODE_CONFNAK;
1037 		if (dont_nak)
1038 		    break;
1039 		if (nb > ao->bsd_bits)
1040 		    nb = ao->bsd_bits;
1041 		else if (nb < BSD_MIN_BITS)
1042 		    nb = BSD_MIN_BITS;
1043 		pv = nakp;
1044 		PUTCHAR(type, nakp);
1045 		PUTCHAR(CILEN_BSD_COMPRESS, nakp);
1046 		PUTCHAR(BSD_MAKE_OPT(BSD_CURRENT_VERSION, nb), nakp);
1047 	    }
1048 
1049 	    /*
1050 	     * Check whether we can do BSD-Compress with the code
1051 	     * size they want.  If the code size is too big, reduce
1052 	     * it until the kernel can cope and nak with that.
1053 	     * We only check this for the first option.
1054 	     */
1055 	    if (p == p0) {
1056 		for (;;) {
1057 		    res = ccp_test(f->unit, pv, CILEN_BSD_COMPRESS, 1);
1058 		    if (res > 0)
1059 			break;
1060 		    if (res < 0 || nb == BSD_MIN_BITS || dont_nak) {
1061 			newret = CODE_CONFREJ;
1062 			break;
1063 		    }
1064 		    if (newret == CODE_CONFACK) {
1065 			BCOPY(pv, nakp, CILEN_BSD_COMPRESS);
1066 			pv = nakp;
1067 			nakp += CILEN_BSD_COMPRESS;
1068 			newret = CODE_CONFNAK;
1069 		    }
1070 		    --nb;
1071 		    pv[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, nb);
1072 		}
1073 	    }
1074 	    break;
1075 
1076 	case CI_PREDICTOR_1:
1077 	    if (!ao->predictor_1) {
1078 		newret = CODE_CONFREJ;
1079 		break;
1080 	    }
1081 
1082 	    ho->predictor_1 = 1;
1083 	    if (clen != CILEN_PREDICTOR_1) {
1084 		newret = CODE_CONFNAK;
1085 		if (dont_nak)
1086 		    break;
1087 		pv = nakp;
1088 		PUTCHAR(type, nakp);
1089 		PUTCHAR(CILEN_PREDICTOR_1, nakp);
1090 	    }
1091 	    if (p == p0 &&
1092 		ccp_test(f->unit, pv, CILEN_PREDICTOR_1, 1) <= 0) {
1093 		newret = CODE_CONFREJ;
1094 	    }
1095 	    break;
1096 
1097 	case CI_PREDICTOR_2:
1098 	    if (!ao->predictor_2) {
1099 		newret = CODE_CONFREJ;
1100 		break;
1101 	    }
1102 
1103 	    ho->predictor_2 = 1;
1104 	    if (clen != CILEN_PREDICTOR_2) {
1105 		newret = CODE_CONFNAK;
1106 		if (dont_nak)
1107 		    break;
1108 		pv = nakp;
1109 		PUTCHAR(type, nakp);
1110 		PUTCHAR(CILEN_PREDICTOR_2, nakp);
1111 	    }
1112 	    if (p == p0 &&
1113 		ccp_test(f->unit, p, CILEN_PREDICTOR_2, 1) <= 0) {
1114 		newret = CODE_CONFREJ;
1115 	    }
1116 	    break;
1117 
1118 	default:
1119 	    newret = CODE_CONFREJ;
1120 	    break;
1121 	}
1122 
1123 	/* Cope with confused peers. */
1124 	if (clen < 2)
1125 	    clen = 2;
1126 
1127 	if (newret == CODE_CONFACK && ret != CODE_CONFACK)
1128 	    continue;
1129 	if (newret == CODE_CONFNAK) {
1130 	    if (dont_nak) {
1131 		newret = CODE_CONFREJ;
1132 	    } else {
1133 		/* Ignore subsequent nakable things if rejecting. */
1134 		if (ret == CODE_CONFREJ)
1135 		    continue;
1136 		ret = CODE_CONFNAK;
1137 	    }
1138 	}
1139 	if (newret == CODE_CONFREJ) {
1140 	    ret = CODE_CONFREJ;
1141 	    if (p != rejp)
1142 		BCOPY(p, rejp, clen);
1143 	    rejp += clen;
1144 	}
1145     }
1146 
1147     switch (ret) {
1148     case CODE_CONFACK:
1149 	*lenp = p - p0;
1150 	break;
1151     case CODE_CONFNAK:
1152 	*lenp = nakp - nak_buffer;
1153 	BCOPY(nak_buffer, p0, *lenp);
1154 	break;
1155     case CODE_CONFREJ:
1156 	*lenp = rejp - p0;
1157 	break;
1158     }
1159     return ret;
1160 }
1161 
1162 /*
1163  * Make a string name for a compression method (or 2).
1164  */
1165 static char *
1166 method_name(opt, opt2)
1167     ccp_options *opt, *opt2;
1168 {
1169     static char result[64];
1170 
1171     if (!ANY_COMPRESS(*opt))
1172 	return "(none)";
1173     switch (opt->method) {
1174     case CI_DEFLATE:
1175     case CI_DEFLATE_DRAFT:
1176 	if (opt2 != NULL && opt2->deflate_size != opt->deflate_size)
1177 	    (void) slprintf(result, sizeof(result), "Deflate%s (%d/%d)",
1178 		     (opt->method == CI_DEFLATE_DRAFT? "(old#)": ""),
1179 		     opt->deflate_size, opt2->deflate_size);
1180 	else
1181 	    (void) slprintf(result, sizeof(result), "Deflate%s (%d)",
1182 		     (opt->method == CI_DEFLATE_DRAFT? "(old#)": ""),
1183 		     opt->deflate_size);
1184 	break;
1185     case CI_BSD_COMPRESS:
1186 	if (opt2 != NULL && opt2->bsd_bits != opt->bsd_bits)
1187 	    (void) slprintf(result, sizeof(result), "BSD-Compress (%d/%d)",
1188 		     opt->bsd_bits, opt2->bsd_bits);
1189 	else
1190 	    (void) slprintf(result, sizeof(result), "BSD-Compress (%d)",
1191 		     opt->bsd_bits);
1192 	break;
1193     case CI_PREDICTOR_1:
1194 	return "Predictor 1";
1195     case CI_PREDICTOR_2:
1196 	return "Predictor 2";
1197 #ifdef CI_STAC
1198     case CI_STAC:
1199 	return "Stac";
1200 #endif
1201 #ifdef CI_MPPC
1202     case CI_MPPC:
1203 	return "MS-PPC";
1204 #endif
1205     default:
1206 	(void) slprintf(result, sizeof(result), "Method %d", opt->method);
1207     }
1208     return result;
1209 }
1210 
1211 /*
1212  * CCP has come up - inform the kernel driver and log a message.
1213  */
1214 static void
1215 ccp_up(f)
1216     fsm *f;
1217 {
1218     ccp_options *go = &ccp_gotoptions[f->unit];
1219     ccp_options *ho = &ccp_hisoptions[f->unit];
1220     char method1[64];
1221 
1222     /*
1223      * We're now open and up (running).
1224      */
1225     ccp_flags_set(f->unit, 1, 1);
1226     if (ANY_COMPRESS(*go)) {
1227 	if (ANY_COMPRESS(*ho)) {
1228 	    if (go->method == ho->method) {
1229 		notice("%s compression enabled", method_name(go, ho));
1230 	    } else {
1231 		(void) strlcpy(method1, method_name(go, NULL), sizeof(method1));
1232 		notice("%s / %s compression enabled",
1233 		       method1, method_name(ho, NULL));
1234 	    }
1235 	} else
1236 	    notice("%s receive decompression enabled", method_name(go, NULL));
1237     } else if (ANY_COMPRESS(*ho))
1238 	notice("%s transmit compression enabled", method_name(ho, NULL));
1239 }
1240 
1241 /*
1242  * CCP has gone down - inform the kernel driver.
1243  */
1244 static void
1245 ccp_down(f)
1246     fsm *f;
1247 {
1248     if (ccp_localstate[f->unit] & RACK_PENDING)
1249 	UNTIMEOUT(ccp_rack_timeout, f);
1250     /* Don't forget about peer's code rejects or ignoring of requests. */
1251     ccp_localstate[f->unit] &= ~RACK_PENDING & ~RREQ_REPEAT;
1252     /* We're still open, but no longer up. */
1253     ccp_flags_set(f->unit, 1, 0);
1254 }
1255 
1256 static int
1257 ccp_printpkt(p, plen, printer, arg)
1258     u_char *p;
1259     int plen;
1260     void (*printer) __P((void *, const char *, ...));
1261     void *arg;
1262 {
1263     u_char *p0, *optend, cichar;
1264     int code, id, len;
1265     int optlen, clen;
1266     u_short cishort;
1267 #ifdef CI_MPPC
1268     u_int32_t cilong;
1269 #endif
1270 
1271     p0 = p;
1272     if (plen < HEADERLEN) {
1273 	printer(arg, "too short (%d<%d)", plen, HEADERLEN);
1274 	return (0);
1275     }
1276     GETCHAR(code, p);
1277     GETCHAR(id, p);
1278     GETSHORT(len, p);
1279 
1280     printer(arg, " %s id=0x%x", code_name(code, 1), id);
1281 
1282     if (len < HEADERLEN) {
1283 	printer(arg, " header length %d<%d", len, HEADERLEN);
1284 	return (HEADERLEN);
1285     }
1286     if (len > plen) {
1287 	printer(arg, " truncated (%d>%d)", len, plen);
1288 	len = plen;
1289     }
1290     len -= HEADERLEN;
1291 
1292     switch (code) {
1293     case CODE_CONFREQ:
1294     case CODE_CONFACK:
1295     case CODE_CONFNAK:
1296     case CODE_CONFREJ:
1297 	/* print list of possible compression methods */
1298 	while (len >= 2) {
1299 	    GETCHAR(code, p);
1300 	    GETCHAR(clen, p);
1301 	    optlen = clen;
1302 	    printer(arg, " <");
1303 	    if (optlen > len)
1304 		optlen = len;
1305 	    if (optlen < 2)
1306 		optlen = 2;
1307 	    len -= optlen;
1308 	    optend = p + optlen - 2;
1309 	    switch (code) {
1310 	    case CI_DEFLATE:
1311 	    case CI_DEFLATE_DRAFT:
1312 		printer(arg, "deflate%s",
1313 		    (code == CI_DEFLATE_DRAFT? "(old#)": ""));
1314 		if (clen != CILEN_DEFLATE)
1315 		    printer(arg, " length %d", clen);
1316 		if (optlen >= CILEN_DEFLATE) {
1317 		    GETCHAR(cichar, p);
1318 		    printer(arg, " %d", DEFLATE_SIZE(cichar));
1319 		    if (DEFLATE_METHOD(cichar) != DEFLATE_METHOD_VAL)
1320 			printer(arg, " method %d", DEFLATE_METHOD(cichar));
1321 		    GETCHAR(cichar, p);
1322 		    if (cichar != DEFLATE_CHK_SEQUENCE)
1323 			printer(arg, " check %d", cichar);
1324 		}
1325 		break;
1326 	    case CI_BSD_COMPRESS:
1327 		printer(arg, "bsd");
1328 		if (clen != CILEN_BSD_COMPRESS)
1329 		    printer(arg, " length %d", clen);
1330 		if (optlen >= CILEN_BSD_COMPRESS) {
1331 		    GETCHAR(cichar, p);
1332 		    printer(arg, " v%d %d", BSD_VERSION(cichar),
1333 			BSD_NBITS(cichar));
1334 		}
1335 		break;
1336 	    case CI_PREDICTOR_1:
1337 		printer(arg, "predictor-1");
1338 		if (clen != CILEN_PREDICTOR_1)
1339 		    printer(arg, " length %d", clen);
1340 		break;
1341 	    case CI_PREDICTOR_2:
1342 		printer(arg, "predictor-2");
1343 		if (clen != CILEN_PREDICTOR_2)
1344 		    printer(arg, " length %d", clen);
1345 		break;
1346 #ifdef CI_STAC
1347 	    case CI_STAC:
1348 		printer(arg, "Stac");
1349 		if (clen != CILEN_STAC)
1350 		    printer(arg, " length %d", clen);
1351 		if (optlen >= CILEN_STAC) {
1352 		    GETSHORT(cishort, p);
1353 		    GETCHAR(cichar, p);
1354 		    printer(arg, " h%d/m%d", cishort, cichar);
1355 		}
1356 		break;
1357 #endif
1358 #ifdef CI_MPPC
1359 	    case CI_MPPC:
1360 		/* There appears to be no good generic name for this one. */
1361 		if (optlen >= CILEN_MPPC) {
1362 		    GETLONG(cilong, p);
1363 		    if (!(cilong & MPPC_COMP)) {
1364 			if (cilong & MPPC_MPPE)
1365 			    printer(arg, "MPPE");
1366 			else
1367 			    printer(arg, "MS-PPC?");
1368 		    } else {
1369 			if (cilong & MPPC_MPPE)
1370 			    printer(arg, "MPPC+MPPE");
1371 			else
1372 			    printer(arg, "MPPC");
1373 		    }
1374 		} else {
1375 		    printer(arg, "MS-?");
1376 		}
1377 		if (clen != CILEN_STAC)
1378 		    printer(arg, " length %d", clen);
1379 		break;
1380 #endif
1381 	    default:
1382 		printer(arg, "typ%d len%d ", code, clen);
1383 		break;
1384 	    }
1385 	    if (p < optend) {
1386 		if (p+8 < optend)
1387 		    printer(arg, " %.8B ...", p);
1388 		else
1389 		    printer(arg, " %.*B", optend-p, p);
1390 		p = optend;
1391 	    }
1392 	    printer(arg, ">");
1393 	}
1394 	break;
1395 
1396     case CODE_TERMACK:
1397     case CODE_TERMREQ:
1398 	if (len > 0) {
1399 	    if (len == 2) {
1400 		GETSHORT(cishort, p);
1401 		printer(arg, " history %d", cishort);
1402 		len = 0;
1403 	    } else if (*p >= ' ' && *p < 0x7f) {
1404 		printer(arg, " ");
1405 		print_string((char *)p, len, printer, arg);
1406 		p += len;
1407 		len = 0;
1408 	    }
1409 	}
1410 	break;
1411     }
1412 
1413     /* dump out the rest of the packet in hex */
1414     if (len > 0) {
1415 	if (len > 8)
1416 	    printer(arg, " %.8B ...", p);
1417 	else
1418 	    printer(arg, " %.*B", len, p);
1419 	p += len;
1420     }
1421 
1422     return p - p0;
1423 }
1424 
1425 /*
1426  * We have received a packet that the decompressor failed to
1427  * decompress.  Here we would expect to issue a reset-request, but
1428  * Motorola has a patent on resetting the compressor as a result of
1429  * detecting an error in the decompressed data after decompression.
1430  * (See US patent 5,130,993; international patent publication number
1431  * WO 91/10289; Australian patent 73296/91.)
1432  *
1433  * So we ask the kernel whether the error was detected after
1434  * decompression; if it was, we take CCP down, thus disabling
1435  * compression :-(, otherwise we issue the reset-request.
1436  */
1437 /*ARGSUSED*/
1438 static void
1439 ccp_datainput(unit, pkt, len)
1440     int unit;
1441     u_char *pkt;
1442     int len;
1443 {
1444     fsm *f;
1445 
1446     f = &ccp_fsm[unit];
1447     if (f->state == OPENED) {
1448 	if (ccp_fatal_error(unit)) {
1449 	    /*
1450 	     * Disable compression by taking CCP down.
1451 	     */
1452 	    error("Lost compression sync: disabling compression");
1453 	    ccp_close(unit, "Lost compression sync");
1454 	} else {
1455 	    /*
1456 	     * Send a reset-request to reset the peer's compressor, if
1457 	     * possible.  We don't do anything if we are still waiting
1458 	     * for an acknowledgement to a previous reset-request (to
1459 	     * avoid flooding the peer).  We reopen CCP if the peer
1460 	     * doesn't like hearing about CCP Reset-Request (Cisco
1461 	     * sends CCP Code-Reject for Reset-Request).  (Reopen
1462 	     * automatically clears the flags and cancels the
1463 	     * timeout.)
1464 	     */
1465 	    if (ccp_localstate[f->unit] & RREQ_REJECTED) {
1466 		dbglog("reopening CCP to reset peer's compressor");
1467 		ccp_open(f->unit);
1468 	    } else if (ccp_localstate[f->unit] & RACK_PENDING) {
1469 		/* Send another reset request; we're out of sequence. */
1470 		ccp_localstate[f->unit] |= RREQ_REPEAT;
1471 	    } else {
1472 		dbglog("sending CCP Reset-Request to reset peer's compressor");
1473 		fsm_sdata(f, CCP_RESETREQ, f->reqid = ++f->id, NULL, 0);
1474 		TIMEOUT(ccp_rack_timeout, f, RACKTIMEOUT);
1475 		ccp_localstate[f->unit] |= RACK_PENDING;
1476 	    }
1477 	}
1478     }
1479 }
1480 
1481 /*
1482  * Timeout waiting for reset-ack.
1483  */
1484 static void
1485 ccp_rack_timeout(arg)
1486     void *arg;
1487 {
1488     fsm *f = arg;
1489 
1490     /* Timeout; no longer pending. */
1491     ccp_localstate[f->unit] &= ~RACK_PENDING;
1492 
1493     /* Frankly, it's a coding flaw if this occurs. */
1494     if (f->state != OPENED)
1495 	return;
1496 
1497     if (ccp_localstate[f->unit] & RREQ_IGNORED) {
1498 	info("peer ignored our CCP Reset-Request twice; reopen instead");
1499 	ccp_localstate[f->unit] =
1500 	    (ccp_localstate[f->unit] & ~RREQ_IGNORED) | RREQ_REJECTED;
1501 	ccp_open(f->unit);
1502     } else if (ccp_localstate[f->unit] & RREQ_REPEAT) {
1503 	dbglog("sending another CCP Reset-Request on timeout");
1504 	fsm_sdata(f, CCP_RESETREQ, f->reqid, NULL, 0);
1505 	TIMEOUT(ccp_rack_timeout, f, RACKTIMEOUT);
1506 	ccp_localstate[f->unit] =
1507 	    (ccp_localstate[f->unit] & ~RREQ_REPEAT) | RREQ_IGNORED |
1508 	    RACK_PENDING;
1509     } else {
1510 	dbglog("timeout waiting for CCP Reset-Ack; hope for the best");
1511 	ccp_localstate[f->unit] |= RREQ_IGNORED;
1512     }
1513 }
1514