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