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
ccp_init(unit)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
ccp_open(unit)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
ccp_close(unit,reason)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
ccp_lowerup(unit)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
ccp_lowerdown(unit)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
ccp_input(unit,p,len)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
ccp_extcode(f,code,id,p,len)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
ccp_protrej(unit)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
ccp_resetci(f)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
ccp_cilen(f)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
ccp_addci(f,p,lenp)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
ccp_ackci(f,p,len)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
ccp_nakci(f,p,len)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
ccp_rejci(f,p,len)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
ccp_reqci(f,p,lenp,dont_nak)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 *
method_name(opt,opt2)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
ccp_up(f)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
ccp_down(f)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
ccp_printpkt(p,plen,printer,arg)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
ccp_datainput(unit,pkt,len)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
ccp_rack_timeout(arg)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