"SfR Fresh" - the SfR Freeware/Shareware Archive 
Member "slirp-1.0.16/src/ppp/ccp.c" of archive slirp-1.0.16.tar.gz:
As a special service "SfR Fresh" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting with prefixed line numbers.
Alternatively you can here view or download the uninterpreted source code file.
That can be also achieved for any archive member file by clicking within an archive contents listing on the first character of the file(path) respectively on the according byte size field.
1 /*
2 * ccp.c - PPP Compression Control Protocol.
3 *
4 * Copyright (c) 1994 The Australian National University.
5 * All rights reserved.
6 *
7 * Permission to use, copy, modify, and distribute this software and its
8 * documentation is hereby granted, provided that the above copyright
9 * notice appears in all copies. This software is provided without any
10 * warranty, express or implied. The Australian National University
11 * makes no representations about the suitability of this software for
12 * any purpose.
13 *
14 * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
15 * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
16 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
17 * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
18 * OF SUCH DAMAGE.
19 *
20 * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
21 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
22 * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
23 * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
24 * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
25 * OR MODIFICATIONS.
26 */
27
28 #ifndef lint
29 static char rcsid[] = "$Id: ccp.c,v 1.10 1995/06/06 01:52:23 paulus Exp $";
30 #endif
31
32 #include <syslog.h>
33 #include <slirp.h>
34 #include "ppp-comp.h"
35
36 #include "pppd.h"
37 #include "fsm.h"
38 #include "ccp.h"
39
40 fsm ccp_fsm[NUM_PPP];
41 ccp_options ccp_wantoptions[NUM_PPP]; /* what to request the peer to use */
42 ccp_options ccp_gotoptions[NUM_PPP]; /* what the peer agreed to do */
43 ccp_options ccp_allowoptions[NUM_PPP]; /* what we'll agree to do */
44 ccp_options ccp_hisoptions[NUM_PPP]; /* what we agreed to do */
45
46 /*
47 * Callbacks for fsm code.
48 */
49 static void ccp_resetci __P((fsm *));
50 static int ccp_cilen __P((fsm *));
51 static void ccp_addci __P((fsm *, u_char *, int *));
52 static int ccp_ackci __P((fsm *, u_char *, int));
53 static int ccp_nakci __P((fsm *, u_char *, int));
54 static int ccp_rejci __P((fsm *, u_char *, int));
55 static int ccp_reqci __P((fsm *, u_char *, int *, int));
56 static void ccp_up __P((fsm *));
57 static void ccp_down __P((fsm *));
58 static int ccp_extcode __P((fsm *, int, int, u_char *, int));
59 static void ccp_rack_timeout __P(());
60
61 static fsm_callbacks ccp_callbacks = {
62 ccp_resetci,
63 ccp_cilen,
64 ccp_addci,
65 ccp_ackci,
66 ccp_nakci,
67 ccp_rejci,
68 ccp_reqci,
69 ccp_up,
70 ccp_down,
71 NULL,
72 NULL,
73 NULL,
74 NULL,
75 ccp_extcode,
76 "CCP"
77 };
78
79 /*
80 * Do we want / did we get any compression?
81 */
82 #define ANY_COMPRESS(opt) ((opt).bsd_compress)
83
84 /*
85 * Local state (mainly for handling reset-reqs and reset-acks
86 */
87 static int ccp_localstate[NUM_PPP];
88 #define RACK_PENDING 1 /* waiting for reset-ack */
89 #define RREQ_REPEAT 2 /* send another reset-req if no reset-ack */
90
91 #define RACKTIMEOUT 1 /* second */
92
93 /*
94 * ccp_init - initialize CCP.
95 */
96 void
97 ccp_init(unit)
98 int unit;
99 {
100 fsm *f = &ccp_fsm[unit];
101
102 f->unit = unit;
103 f->protocol = PPP_CCP;
104 f->callbacks = &ccp_callbacks;
105 fsm_init(f);
106
107 memset(&ccp_wantoptions[unit], 0, sizeof(ccp_options));
108 memset(&ccp_gotoptions[unit], 0, sizeof(ccp_options));
109 memset(&ccp_allowoptions[unit], 0, sizeof(ccp_options));
110 memset(&ccp_hisoptions[unit], 0, sizeof(ccp_options));
111
112 ccp_wantoptions[0].bsd_compress = 1;
113 ccp_wantoptions[0].bsd_bits = 12; /* default value */
114
115 ccp_allowoptions[0].bsd_compress = 1;
116 ccp_allowoptions[0].bsd_bits = BSD_MAX_BITS;
117 }
118
119 /*
120 * ccp_open - CCP is allowed to come up.
121 */
122 void
123 ccp_open(unit)
124 int unit;
125 {
126 fsm *f = &ccp_fsm[unit];
127
128 if (f->state != OPENED)
129 ccp_flags_set(unit, 1, 0);
130 if (!ANY_COMPRESS(ccp_wantoptions[unit]))
131 f->flags |= OPT_SILENT;
132 fsm_open(f);
133 }
134
135 /*
136 * ccp_close - Terminate CCP.
137 */
138 void
139 ccp_close(unit)
140 int unit;
141 {
142 ccp_flags_set(unit, 0, 0);
143 fsm_close(&ccp_fsm[unit]);
144 }
145
146 /*
147 * ccp_lowerup - we may now transmit CCP packets.
148 */
149 void
150 ccp_lowerup(unit)
151 int unit;
152 {
153 fsm_lowerup(&ccp_fsm[unit]);
154 }
155
156 /*
157 * ccp_lowerdown - we may not transmit CCP packets.
158 */
159 void
160 ccp_lowerdown(unit)
161 int unit;
162 {
163 fsm_lowerdown(&ccp_fsm[unit]);
164 }
165
166 /*
167 * ccp_input - process a received CCP packet.
168 */
169 void
170 ccp_input(unit, p, len)
171 int unit;
172 u_char *p;
173 int len;
174 {
175 fsm *f = &ccp_fsm[unit];
176 int oldstate;
177
178 /*
179 * Check for a terminate-request so we can print a message.
180 */
181 oldstate = f->state;
182 fsm_input(f, p, len);
183 if (oldstate == OPENED && p[0] == TERMREQ && f->state != OPENED)
184 do_syslog(LOG_NOTICE, "Compression disabled by peer.");
185
186 /*
187 * If we get a terminate-ack and we're not asking for compression,
188 * close CCP.
189 */
190 if (oldstate == REQSENT && p[0] == TERMACK
191 && !ANY_COMPRESS(ccp_gotoptions[unit]))
192 ccp_close(unit);
193
194 }
195
196 /*
197 * Handle a CCP-specific code.
198 */
199 static int
200 ccp_extcode(f, code, id, p, len)
201 fsm *f;
202 int code, id;
203 u_char *p;
204 int len;
205 {
206 switch (code) {
207 case CCP_RESETREQ:
208 if (f->state != OPENED)
209 break;
210 /* send a reset-ack, which the transmitter will see and
211 reset its compression state. */
212 fsm_sdata(f, CCP_RESETACK, id, NULL, 0);
213 break;
214
215 case CCP_RESETACK:
216 if (ccp_localstate[f->unit] & RACK_PENDING && id == f->reqid) {
217 ccp_localstate[f->unit] &= ~(RACK_PENDING | RREQ_REPEAT);
218 UNTIMEOUT(ccp_rack_timeout, (caddr_t) f);
219 }
220 break;
221
222 default:
223 return 0;
224 }
225
226 return 1;
227 }
228
229 /*
230 * ccp_protrej - peer doesn't talk CCP.
231 */
232 void
233 ccp_protrej(unit)
234 int unit;
235 {
236 ccp_flags_set(unit, 0, 0);
237 fsm_lowerdown(&ccp_fsm[unit]);
238 }
239
240 /*
241 * ccp_resetci - initialize at start of negotiation.
242 */
243 static void
244 ccp_resetci(f)
245 fsm *f;
246 {
247 ccp_options *go = &ccp_gotoptions[f->unit];
248 u_char opt_buf[16];
249
250 *go = ccp_wantoptions[f->unit];
251 if (go->bsd_compress) {
252 opt_buf[0] = CI_BSD_COMPRESS;
253 opt_buf[1] = CILEN_BSD_COMPRESS;
254 opt_buf[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits);
255 if (!ccp_test(f->unit, opt_buf, CILEN_BSD_COMPRESS, 0))
256 go->bsd_compress = 0;
257 }
258 }
259
260 /*
261 * ccp_cilen - Return total length of our configuration info.
262 */
263 static int
264 ccp_cilen(f)
265 fsm *f;
266 {
267 ccp_options *go = &ccp_gotoptions[f->unit];
268
269 return (go->bsd_compress? CILEN_BSD_COMPRESS: 0);
270 }
271
272 /*
273 * ccp_addci - put our requests in a packet.
274 */
275 static void
276 ccp_addci(f, p, lenp)
277 fsm *f;
278 u_char *p;
279 int *lenp;
280 {
281 ccp_options *go = &ccp_gotoptions[f->unit];
282 u_char *p0 = p;
283
284 if (go->bsd_compress) {
285 p[0] = CI_BSD_COMPRESS;
286 p[1] = CILEN_BSD_COMPRESS;
287 p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits);
288 if (ccp_test(f->unit, p, CILEN_BSD_COMPRESS, 0))
289 p += CILEN_BSD_COMPRESS;
290 else
291 go->bsd_compress = 0;
292 }
293 *lenp = p - p0;
294 }
295
296 /*
297 * ccp_ackci - process a received configure-ack, and return
298 * 1 iff the packet was OK.
299 */
300 static int
301 ccp_ackci(f, p, len)
302 fsm *f;
303 u_char *p;
304 int len;
305 {
306 ccp_options *go = &ccp_gotoptions[f->unit];
307
308 if (go->bsd_compress) {
309 if (len < CILEN_BSD_COMPRESS
310 || p[0] != CI_BSD_COMPRESS || p[1] != CILEN_BSD_COMPRESS
311 || p[2] != BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits))
312 return 0;
313 p += CILEN_BSD_COMPRESS;
314 len -= CILEN_BSD_COMPRESS;
315 }
316 if (len != 0)
317 return 0;
318 return 1;
319 }
320
321 /*
322 * ccp_nakci - process received configure-nak.
323 * Returns 1 iff the nak was OK.
324 */
325 static int
326 ccp_nakci(f, p, len)
327 fsm *f;
328 u_char *p;
329 int len;
330 {
331 ccp_options *go = &ccp_gotoptions[f->unit];
332 ccp_options no; /* options we've seen already */
333 ccp_options try; /* options to ask for next time */
334
335 memset(&no, 0, sizeof(no));
336 try = *go;
337
338 if (go->bsd_compress && !no.bsd_compress && len >= CILEN_BSD_COMPRESS
339 && p[0] == CI_BSD_COMPRESS && p[1] == CILEN_BSD_COMPRESS) {
340 no.bsd_compress = 1;
341 /*
342 * Peer wants us to use a different number of bits
343 * or a different version.
344 */
345 if (BSD_VERSION(p[2]) != BSD_CURRENT_VERSION)
346 try.bsd_compress = 0;
347 else if (BSD_NBITS(p[2]) < go->bsd_bits)
348 try.bsd_bits = BSD_NBITS(p[2]);
349 p += CILEN_BSD_COMPRESS;
350 len -= CILEN_BSD_COMPRESS;
351 }
352
353 /*
354 * Have a look at any remaining options...???
355 */
356
357 if (len != 0)
358 return 0;
359
360 if (f->state != OPENED)
361 *go = try;
362 return 1;
363 }
364
365 /*
366 * ccp_rejci - reject some of our suggested compression methods.
367 */
368 static int
369 ccp_rejci(f, p, len)
370 fsm *f;
371 u_char *p;
372 int len;
373 {
374 ccp_options *go = &ccp_gotoptions[f->unit];
375 ccp_options try; /* options to request next time */
376
377 try = *go;
378
379 if (go->bsd_compress && len >= CILEN_BSD_COMPRESS
380 && p[0] == CI_BSD_COMPRESS && p[1] == CILEN_BSD_COMPRESS) {
381 if (p[2] != BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits))
382 return 0;
383 try.bsd_compress = 0;
384 p += CILEN_BSD_COMPRESS;
385 len -= CILEN_BSD_COMPRESS;
386 }
387
388 if (len != 0)
389 return 0;
390
391 if (f->state != OPENED)
392 *go = try;
393
394 return 1;
395 }
396
397 /*
398 * ccp_reqci - processed a received configure-request.
399 * Returns CONFACK, CONFNAK or CONFREJ and the packet modified
400 * appropriately.
401 */
402 static int
403 ccp_reqci(f, p, lenp, dont_nak)
404 fsm *f;
405 u_char *p;
406 int *lenp;
407 int dont_nak;
408 {
409 int ret, newret;
410 u_char *p0, *retp;
411 int len, clen, type, nb;
412 ccp_options *ho = &ccp_hisoptions[f->unit];
413 ccp_options *ao = &ccp_allowoptions[f->unit];
414
415 ret = CONFACK;
416 retp = p0 = p;
417 len = *lenp;
418
419 memset(ho, 0, sizeof(ccp_options));
420
421 while (len > 0) {
422 newret = CONFACK;
423 if (len < 2 || p[1] < 2 || p[1] > len) {
424 /* length is bad */
425 clen = len;
426 newret = CONFREJ;
427
428 } else {
429 type = p[0];
430 clen = p[1];
431
432 switch (type) {
433 case CI_BSD_COMPRESS:
434 if (!ao->bsd_compress || clen != CILEN_BSD_COMPRESS) {
435 newret = CONFREJ;
436 break;
437 }
438
439 ho->bsd_compress = 1;
440 ho->bsd_bits = nb = BSD_NBITS(p[2]);
441 if (BSD_VERSION(p[2]) != BSD_CURRENT_VERSION
442 || nb > ao->bsd_bits) {
443 newret = CONFNAK;
444 nb = ao->bsd_bits;
445 } else if (nb < BSD_MIN_BITS) {
446 newret = CONFREJ;
447 } else if (!ccp_test(f->unit, p, CILEN_BSD_COMPRESS, 1)) {
448 if (nb > BSD_MIN_BITS) {
449 --nb;
450 newret = CONFNAK;
451 } else
452 newret = CONFREJ;
453 }
454 if (newret == CONFNAK && !dont_nak) {
455 p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, nb);
456 }
457
458 break;
459
460 default:
461 newret = CONFREJ;
462 }
463 }
464
465 if (newret == CONFNAK && dont_nak)
466 newret = CONFREJ;
467 if (!(newret == CONFACK || newret == CONFNAK && ret == CONFREJ)) {
468 /* we're returning this option */
469 if (newret == CONFREJ && ret == CONFNAK)
470 retp = p0;
471 ret = newret;
472 if (p != retp)
473 BCOPY(p, retp, clen);
474 retp += clen;
475 }
476
477 p += clen;
478 len -= clen;
479 }
480
481 if (ret != CONFACK)
482 *lenp = retp - p0;
483 return ret;
484 }
485
486 /*
487 * CCP has come up - inform the kernel driver.
488 */
489 static void
490 ccp_up(f)
491 fsm *f;
492 {
493 ccp_options *go = &ccp_gotoptions[f->unit];
494 ccp_options *ho = &ccp_hisoptions[f->unit];
495
496 ccp_flags_set(f->unit, 1, 1);
497 if (go->bsd_compress || ho->bsd_compress)
498 do_syslog(LOG_NOTICE, "%s enabled",
499 go->bsd_compress? ho->bsd_compress? "Compression":
500 "Receive compression": "Transmit compression");
501 }
502
503 /*
504 * CCP has gone down - inform the kernel driver.
505 */
506 static void
507 ccp_down(f)
508 fsm *f;
509 {
510 if (ccp_localstate[f->unit] & RACK_PENDING)
511 UNTIMEOUT(ccp_rack_timeout, (caddr_t) f);
512 ccp_localstate[f->unit] = 0;
513 ccp_flags_set(f->unit, 1, 0);
514 }
515
516 /*
517 * Print the contents of a CCP packet.
518 */
519 char *ccp_codenames[] = {
520 "ConfReq", "ConfAck", "ConfNak", "ConfRej",
521 "TermReq", "TermAck", "CodeRej",
522 NULL, NULL, NULL, NULL, NULL, NULL,
523 "ResetReq", "ResetAck",
524 };
525
526 int
527 ccp_printpkt(p, plen, printer, arg)
528 u_char *p;
529 int plen;
530 void (*printer) __P((void *, char *, ...));
531 void *arg;
532 {
533 u_char *p0, *optend;
534 int code, id, len;
535 int optlen;
536
537 p0 = p;
538 if (plen < HEADERLEN)
539 return 0;
540 code = p[0];
541 id = p[1];
542 len = (p[2] << 8) + p[3];
543 if (len < HEADERLEN || len > plen)
544 return 0;
545
546 if (code >= 1 && code <= sizeof(ccp_codenames) / sizeof(char *)
547 && ccp_codenames[code-1] != NULL)
548 printer(arg, " %s", ccp_codenames[code-1]);
549 else
550 printer(arg, " code=0x%x", code);
551 printer(arg, " id=0x%x", id);
552 len -= HEADERLEN;
553 p += HEADERLEN;
554
555 switch (code) {
556 case CONFREQ:
557 case CONFACK:
558 case CONFNAK:
559 case CONFREJ:
560 /* print list of possible compression methods */
561 while (len >= 2) {
562 code = p[0];
563 optlen = p[1];
564 if (optlen < 2 || optlen > len)
565 break;
566 printer(arg, " <");
567 len -= optlen;
568 optend = p + optlen;
569 switch (code) {
570 case CI_BSD_COMPRESS:
571 if (optlen >= CILEN_BSD_COMPRESS) {
572 printer(arg, "bsd v%d %d", BSD_VERSION(p[2]),
573 BSD_NBITS(p[2]));
574 p += CILEN_BSD_COMPRESS;
575 }
576 break;
577 }
578 while (p < optend)
579 printer(arg, " %.2x", *p++);
580 printer(arg, ">");
581 }
582 break;
583 }
584
585 /* dump out the rest of the packet in hex */
586 while (--len >= 0)
587 printer(arg, " %.2x", *p++);
588
589 return p - p0;
590 }
591
592 /*
593 * We have received a packet that the decompressor failed to
594 * decompress. Here we would expect to issue a reset-request, but
595 * Motorola has a patent on resetting the compressor as a result of
596 * detecting an error in the decompressed data after decompression.
597 * (See US patent 5,130,993; international patent publication number
598 * WO 91/10289; Australian patent 73296/91.)
599 *
600 * So we ask the kernel whether the error was detected after
601 * decompression; if it was, we take CCP down, thus disabling
602 * compression :-(, otherwise we issue the reset-request.
603 */
604 void
605 ccp_datainput(unit, pkt, len)
606 int unit;
607 u_char *pkt;
608 int len;
609 {
610 fsm *f;
611
612 f = &ccp_fsm[unit];
613 if (f->state == OPENED) {
614 if (ccp_fatal_error(unit)) {
615 /*
616 * Disable compression by taking CCP down.
617 */
618 do_syslog(LOG_ERR, "Lost compression sync: disabling compression");
619 ccp_close(unit);
620 } else {
621 /*
622 * Send a reset-request to reset the peer's compressor.
623 * We don't do that if we are still waiting for an
624 * acknowledgement to a previous reset-request.
625 */
626 if (!(ccp_localstate[f->unit] & RACK_PENDING)) {
627 fsm_sdata(f, CCP_RESETREQ, f->reqid = ++f->id, NULL, 0);
628 TIMEOUT(ccp_rack_timeout, (caddr_t) f, RACKTIMEOUT);
629 ccp_localstate[f->unit] |= RACK_PENDING;
630 } else
631 ccp_localstate[f->unit] |= RREQ_REPEAT;
632 }
633 }
634 }
635
636 /*
637 * Timeout waiting for reset-ack.
638 */
639 static void
640 ccp_rack_timeout(arg)
641 caddr_t arg;
642 {
643 fsm *f = (fsm *) arg;
644
645 if (f->state == OPENED && ccp_localstate[f->unit] & RREQ_REPEAT) {
646 fsm_sdata(f, CCP_RESETREQ, f->reqid, NULL, 0);
647 TIMEOUT(ccp_rack_timeout, (caddr_t) f, RACKTIMEOUT);
648 ccp_localstate[f->unit] &= ~RREQ_REPEAT;
649 } else
650 ccp_localstate[f->unit] &= ~RACK_PENDING;
651 }
652