2 * ccp.c - PPP Compression Control Protocol.
6 static char rcsid[] = "$Id: ccp.c,v 1.2 1994/08/22 00:38:36 paulus Exp $";
10 #include <sys/ioctl.h>
18 ccp_options ccp_wantoptions[NPPP]; /* what to request the peer to use */
19 ccp_options ccp_gotoptions[NPPP]; /* what the peer agreed to do */
20 ccp_options ccp_allowoptions[NPPP]; /* what we'll agree to do */
21 ccp_options ccp_hisoptions[NPPP]; /* what we agreed to do */
24 * Callbacks for fsm code.
26 static void ccp_resetci __ARGS((fsm *));
27 static int ccp_cilen __ARGS((fsm *));
28 static void ccp_addci __ARGS((fsm *, u_char *, int *));
29 static int ccp_ackci __ARGS((fsm *, u_char *, int));
30 static int ccp_nakci __ARGS((fsm *, u_char *, int));
31 static int ccp_rejci __ARGS((fsm *, u_char *, int));
32 static int ccp_reqci __ARGS((fsm *, u_char *, int *, int));
33 static void ccp_up __ARGS((fsm *));
34 static void ccp_down __ARGS((fsm *));
35 static int ccp_extcode __ARGS((fsm *, int, int, u_char *, int));
36 static void ccp_rack_timeout __ARGS(());
38 static fsm_callbacks ccp_callbacks = {
57 * Length of configuration options, which describe possible
58 * compression methods.
63 * Configuration option values for compression methods.
65 #define CI_BSD_COMPRESS 0x21
68 * Local state (mainly for handling reset-reqs and reset-acks
70 static int ccp_localstate[NPPP];
71 #define RACK_PENDING 1 /* waiting for reset-ack */
72 #define RREQ_REPEAT 2 /* send another reset-req if no reset-ack */
74 #define RACKTIMEOUT 1 /* second */
77 * ccp_init - initialize CCP.
83 fsm *f = &ccp_fsm[unit];
87 f->callbacks = &ccp_callbacks;
90 memset(&ccp_wantoptions[unit], 0, sizeof(ccp_options));
91 memset(&ccp_gotoptions[unit], 0, sizeof(ccp_options));
92 memset(&ccp_allowoptions[unit], 0, sizeof(ccp_options));
93 memset(&ccp_hisoptions[unit], 0, sizeof(ccp_options));
95 ccp_wantoptions[0].bsd_bits = 12; /* default value */
97 ccp_allowoptions[0].bsd_compress = 1;
98 ccp_allowoptions[0].bsd_bits = MAX_BSD_BITS;
102 * ccp_open - CCP is allowed to come up.
108 fsm *f = &ccp_fsm[unit];
110 if (f->state != OPENED)
111 ccp_flags_set(unit, 1, 0);
112 if (!ccp_wantoptions[unit].bsd_compress)
113 f->flags |= OPT_SILENT;
118 * ccp_close - Terminate CCP.
124 ccp_flags_set(unit, 0, 0);
125 fsm_close(&ccp_fsm[unit]);
129 * ccp_lowerup - we may now transmit CCP packets.
135 fsm_lowerup(&ccp_fsm[unit]);
139 * ccp_lowerdown - we may not transmit CCP packets.
145 fsm_lowerdown(&ccp_fsm[unit]);
149 * ccp_input - process a received CCP packet.
152 ccp_input(unit, p, len)
157 fsm_input(&ccp_fsm[unit], p, len);
161 * Handle a CCP-specific code.
164 ccp_extcode(f, code, id, p, len)
172 if (f->state != OPENED)
174 /* send a reset-ack, which the transmitter will see and
175 reset its compression state. */
176 fsm_sdata(f, RESETACK, id, NULL, 0);
180 if (ccp_localstate[f->unit] & RACK_PENDING && id == f->reqid) {
181 ccp_localstate[f->unit] &= ~(RACK_PENDING | RREQ_REPEAT);
182 UNTIMEOUT(ccp_rack_timeout, (caddr_t) f);
194 * ccp_protrej - peer doesn't talk CCP.
200 ccp_flags_set(unit, 0, 0);
201 fsm_lowerdown(&ccp_fsm[unit]);
205 * ccp_resetci - initialize at start of negotiation.
211 ccp_options *go = &ccp_gotoptions[f->unit];
214 *go = ccp_wantoptions[f->unit];
215 if (go->bsd_compress) {
216 opt_buf[0] = CI_BSD_COMPRESS;
217 opt_buf[1] = CILEN_BSD;
218 opt_buf[2] = go->bsd_bits;
219 if (!ccp_test(f->unit, opt_buf, 3, 0))
220 go->bsd_compress = 0;
225 * ccp_cilen - Return total length of our configuration info.
231 ccp_options *go = &ccp_gotoptions[f->unit];
233 return (go->bsd_compress? CILEN_BSD: 0);
237 * ccp_addci - put our requests in a packet.
240 ccp_addci(f, p, lenp)
245 ccp_options *go = &ccp_gotoptions[f->unit];
248 if (go->bsd_compress) {
249 p[0] = CI_BSD_COMPRESS;
258 * ccp_ackci - process a received configure-ack, and return
259 * 1 iff the packet was OK.
267 ccp_options *go = &ccp_gotoptions[f->unit];
269 if (go->bsd_compress) {
270 if (len != 3 || p[0] != CI_BSD_COMPRESS
271 || p[1] != CILEN_BSD || p[2] != go->bsd_bits)
282 * ccp_nakci - process received configure-nak.
283 * Returns 1 iff the nak was OK.
291 ccp_options *go = &ccp_gotoptions[f->unit];
292 ccp_options no; /* options we've seen already */
293 ccp_options try; /* options to ask for next time */
295 memset(&no, 0, sizeof(no));
298 if (go->bsd_compress && len >= CILEN_BSD && p[0] == CI_BSD_COMPRESS
299 && p[1] == CILEN_BSD) {
302 * Peer wants us to use a different number of bits.
304 if (p[2] < go->bsd_bits)
311 * Have a look at any remaining options...???
317 if (f->state != OPENED)
323 * ccp_rejci - reject some of our suggested compression methods.
331 ccp_options *go = &ccp_gotoptions[f->unit];
332 ccp_options try; /* options to request next time */
336 if (go->bsd_compress && len >= CILEN_BSD && p[0] == CI_BSD_COMPRESS
337 && p[1] == CILEN_BSD) {
338 if (p[2] != go->bsd_bits)
340 try.bsd_compress = 0;
348 if (f->state != OPENED)
355 * ccp_reqci - processed a received configure-request.
356 * Returns CONFACK, CONFNAK or CONFREJ and the packet modified
360 ccp_reqci(f, p, lenp, dont_nak)
369 ccp_options *ho = &ccp_hisoptions[f->unit];
370 ccp_options *ao = &ccp_allowoptions[f->unit];
376 memset(ho, 0, sizeof(ccp_options));
380 if (len < 2 || p[1] < 2 || p[1] > len) {
390 case CI_BSD_COMPRESS:
391 if (!ao->bsd_compress || clen != CILEN_BSD) {
396 ho->bsd_compress = 1;
398 if (ho->bsd_bits < MIN_BSD_BITS
399 || ho->bsd_bits > ao->bsd_bits) {
401 } else if (!ccp_test(f->unit, p, CILEN_BSD, 1)) {
402 if (ho->bsd_bits > MIN_BSD_BITS)
407 if (newret == CONFNAK && !dont_nak) {
408 p[2] = (ho->bsd_bits < ao->bsd_bits? MIN_BSD_BITS:
419 if (!(newret == CONFACK || newret == CONFNAK && ret == CONFREJ)) {
420 /* we're returning this option */
423 BCOPY(p, retp, clen);
437 * CCP has come up - inform the kernel driver.
443 ccp_flags_set(f->unit, 1, 1);
447 * CCP has gone down - inform the kernel driver.
453 if (ccp_localstate[f->unit] & RACK_PENDING)
454 UNTIMEOUT(ccp_rack_timeout, (caddr_t) f);
455 ccp_localstate[f->unit] = 0;
456 ccp_flags_set(f->unit, 1, 0);
460 * Print the contents of a CCP packet.
462 char *ccp_codenames[] = {
463 "ConfReq", "ConfAck", "ConfNak", "ConfRej",
464 "TermReq", "TermAck", "CodeRej",
465 NULL, NULL, NULL, NULL, NULL, NULL,
466 "ResetReq", "ResetAck",
470 ccp_printpkt(p, plen, printer, arg)
473 void (*printer) __ARGS((void *, char *, ...));
481 if (plen < HEADERLEN)
485 len = (p[2] << 8) + p[3];
486 if (len < HEADERLEN || len > plen)
489 if (code >= 1 && code <= sizeof(ccp_codenames) / sizeof(char *)
490 && ccp_codenames[code-1] != NULL)
491 printer(arg, " %s", ccp_codenames[code-1]);
493 printer(arg, " code=0x%x", code);
494 printer(arg, " id=0x%x", id);
503 /* print list of possible compression methods */
507 if (optlen < 2 || optlen > len)
513 case CI_BSD_COMPRESS:
514 if (optlen >= CILEN_BSD) {
515 printer(arg, "bsd %d", p[2]);
521 printer(arg, " %.2x", *p++);
527 /* dump out the rest of the packet in hex */
529 printer(arg, " %.2x", *p++);
535 * We have received a packet that the decompressor failed to decompress.
536 * Issue a reset-req (if we haven't issued one recently).
539 ccp_datainput(unit, pkt, len)
547 if (f->state == OPENED) {
548 if (!(ccp_localstate[unit] & RACK_PENDING)) {
549 fsm_sdata(f, RESETREQ, f->reqid = ++f->id, NULL, 0);
550 TIMEOUT(ccp_rack_timeout, (caddr_t) f, RACKTIMEOUT);
551 ccp_localstate[unit] |= RACK_PENDING;
553 ccp_localstate[unit] |= RREQ_REPEAT;
558 * Timeout waiting for reset-ack.
561 ccp_rack_timeout(arg)
564 fsm *f = (fsm *) arg;
566 if (f->state == OPENED && ccp_localstate[f->unit] & RREQ_REPEAT) {
567 fsm_sdata(f, RESETREQ, f->reqid, NULL, 0);
568 TIMEOUT(ccp_rack_timeout, (caddr_t) f, RACKTIMEOUT);
569 ccp_localstate[f->unit] &= ~RREQ_REPEAT;
571 ccp_localstate[f->unit] &= ~RACK_PENDING;