X-Git-Url: http://git.ozlabs.org/?p=ppp.git;a=blobdiff_plain;f=pppd%2Fccp.c;h=0ecfc97e281233099182818c316621580f697732;hp=5e90ce6ecf42dc25400d8021058a9fd163429b92;hb=ce9491a4b11f694af7e4cd628272ac2abb121850;hpb=045d19436a083f9c180993ff35a68597af65bc12 diff --git a/pppd/ccp.c b/pppd/ccp.c index 5e90ce6..0ecfc97 100644 --- a/pppd/ccp.c +++ b/pppd/ccp.c @@ -1,39 +1,62 @@ /* * ccp.c - PPP Compression Control Protocol. + * + * Copyright (c) 1994 The Australian National University. + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation is hereby granted, provided that the above copyright + * notice appears in all copies. This software is provided without any + * warranty, express or implied. The Australian National University + * makes no representations about the suitability of this software for + * any purpose. + * + * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY + * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF + * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO + * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, + * OR MODIFICATIONS. */ #ifndef lint -static char rcsid[] = "$Id: ccp.c,v 1.1 1994/08/11 01:44:32 paulus Exp $"; +static char rcsid[] = "$Id: ccp.c,v 1.9 1995/05/19 03:17:09 paulus Exp $"; #endif #include #include +#include #include "pppd.h" -#include "ppp.h" #include "fsm.h" #include "ccp.h" -fsm ccp_fsm[NPPP]; -ccp_options ccp_wantoptions[NPPP]; /* what to request the peer to use */ -ccp_options ccp_gotoptions[NPPP]; /* what the peer agreed to do */ -ccp_options ccp_allowoptions[NPPP]; /* what we'll agree to do */ -ccp_options ccp_hisoptions[NPPP]; /* what we agreed to do */ +fsm ccp_fsm[NUM_PPP]; +ccp_options ccp_wantoptions[NUM_PPP]; /* what to request the peer to use */ +ccp_options ccp_gotoptions[NUM_PPP]; /* what the peer agreed to do */ +ccp_options ccp_allowoptions[NUM_PPP]; /* what we'll agree to do */ +ccp_options ccp_hisoptions[NUM_PPP]; /* what we agreed to do */ /* * Callbacks for fsm code. */ -static void ccp_resetci __ARGS((fsm *)); -static int ccp_cilen __ARGS((fsm *)); -static void ccp_addci __ARGS((fsm *, u_char *, int *)); -static int ccp_ackci __ARGS((fsm *, u_char *, int)); -static int ccp_nakci __ARGS((fsm *, u_char *, int)); -static int ccp_rejci __ARGS((fsm *, u_char *, int)); -static int ccp_reqci __ARGS((fsm *, u_char *, int *, int)); -static void ccp_up __ARGS((fsm *)); -static void ccp_down __ARGS((fsm *)); -static int ccp_extcode __ARGS((fsm *, int, int, u_char *, int)); -static void ccp_rack_timeout __ARGS(()); +static void ccp_resetci __P((fsm *)); +static int ccp_cilen __P((fsm *)); +static void ccp_addci __P((fsm *, u_char *, int *)); +static int ccp_ackci __P((fsm *, u_char *, int)); +static int ccp_nakci __P((fsm *, u_char *, int)); +static int ccp_rejci __P((fsm *, u_char *, int)); +static int ccp_reqci __P((fsm *, u_char *, int *, int)); +static void ccp_up __P((fsm *)); +static void ccp_down __P((fsm *)); +static int ccp_extcode __P((fsm *, int, int, u_char *, int)); +static void ccp_rack_timeout __P(()); static fsm_callbacks ccp_callbacks = { ccp_resetci, @@ -54,20 +77,14 @@ static fsm_callbacks ccp_callbacks = { }; /* - * Length of configuration options, which describe possible - * compression methods. + * Do we want / did we get any compression? */ -#define CILEN_BSD 3 - -/* - * Configuration option values for compression methods. - */ -#define CI_BSD_COMPRESS 0x21 +#define ANY_COMPRESS(opt) ((opt).bsd_compress) /* * Local state (mainly for handling reset-reqs and reset-acks */ -static int ccp_localstate[NPPP]; +static int ccp_localstate[NUM_PPP]; #define RACK_PENDING 1 /* waiting for reset-ack */ #define RREQ_REPEAT 2 /* send another reset-req if no reset-ack */ @@ -83,7 +100,7 @@ ccp_init(unit) fsm *f = &ccp_fsm[unit]; f->unit = unit; - f->protocol = CCP; + f->protocol = PPP_CCP; f->callbacks = &ccp_callbacks; fsm_init(f); @@ -95,7 +112,7 @@ ccp_init(unit) ccp_wantoptions[0].bsd_bits = 12; /* default value */ ccp_allowoptions[0].bsd_compress = 1; - ccp_allowoptions[0].bsd_bits = MAX_BSD_BITS; + ccp_allowoptions[0].bsd_bits = BSD_MAX_BITS; } /* @@ -109,6 +126,8 @@ ccp_open(unit) if (f->state != OPENED) ccp_flags_set(unit, 1, 0); + if (!ANY_COMPRESS(ccp_wantoptions[unit])) + f->flags |= OPT_SILENT; fsm_open(f); } @@ -152,7 +171,16 @@ ccp_input(unit, p, len) u_char *p; int len; { - fsm_input(&ccp_fsm[unit], p, len); + fsm *f = &ccp_fsm[unit]; + int oldstate; + + /* + * Check for a terminate-request so we can print a message. + */ + oldstate = f->state; + fsm_input(f, p, len); + if (oldstate == OPENED && p[0] == TERMREQ && f->state != OPENED) + syslog(LOG_NOTICE, "Compression disabled by peer."); } /* @@ -166,15 +194,15 @@ ccp_extcode(f, code, id, p, len) int len; { switch (code) { - case RESETREQ: + case CCP_RESETREQ: if (f->state != OPENED) break; /* send a reset-ack, which the transmitter will see and reset its compression state. */ - fsm_sdata(f, RESETACK, id, NULL, 0); + fsm_sdata(f, CCP_RESETACK, id, NULL, 0); break; - case RESETACK: + case CCP_RESETACK: if (ccp_localstate[f->unit] & RACK_PENDING && id == f->reqid) { ccp_localstate[f->unit] &= ~(RACK_PENDING | RREQ_REPEAT); UNTIMEOUT(ccp_rack_timeout, (caddr_t) f); @@ -206,7 +234,17 @@ static void ccp_resetci(f) fsm *f; { - ccp_gotoptions[f->unit] = ccp_wantoptions[f->unit]; + ccp_options *go = &ccp_gotoptions[f->unit]; + u_char opt_buf[16]; + + *go = ccp_wantoptions[f->unit]; + if (go->bsd_compress) { + opt_buf[0] = CI_BSD_COMPRESS; + opt_buf[1] = CILEN_BSD_COMPRESS; + opt_buf[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits); + if (!ccp_test(f->unit, opt_buf, CILEN_BSD_COMPRESS, 0)) + go->bsd_compress = 0; + } } /* @@ -218,7 +256,7 @@ ccp_cilen(f) { ccp_options *go = &ccp_gotoptions[f->unit]; - return (go->bsd_compress? CILEN_BSD: 0); + return (go->bsd_compress? CILEN_BSD_COMPRESS: 0); } /* @@ -235,9 +273,12 @@ ccp_addci(f, p, lenp) if (go->bsd_compress) { p[0] = CI_BSD_COMPRESS; - p[1] = CILEN_BSD; - p[2] = go->bsd_bits; - p += 3; + p[1] = CILEN_BSD_COMPRESS; + p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits); + if (ccp_test(f->unit, p, CILEN_BSD_COMPRESS, 0)) + p += CILEN_BSD_COMPRESS; + else + go->bsd_compress = 0; } *lenp = p - p0; } @@ -255,11 +296,12 @@ ccp_ackci(f, p, len) ccp_options *go = &ccp_gotoptions[f->unit]; if (go->bsd_compress) { - if (len != 3 || p[0] != CI_BSD_COMPRESS - || p[1] != CILEN_BSD || p[2] != go->bsd_bits) + if (len < CILEN_BSD_COMPRESS + || p[0] != CI_BSD_COMPRESS || p[1] != CILEN_BSD_COMPRESS + || p[2] != BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits)) return 0; - p += 3; - len -= 3; + p += CILEN_BSD_COMPRESS; + len -= CILEN_BSD_COMPRESS; } if (len != 0) return 0; @@ -283,16 +325,19 @@ ccp_nakci(f, p, len) memset(&no, 0, sizeof(no)); try = *go; - if (go->bsd_compress && len >= CILEN_BSD && p[0] == CI_BSD_COMPRESS - && p[1] == CILEN_BSD) { + if (go->bsd_compress && !no.bsd_compress && len >= CILEN_BSD_COMPRESS + && p[0] == CI_BSD_COMPRESS && p[1] == CILEN_BSD_COMPRESS) { no.bsd_compress = 1; /* - * Peer wants us to use a different number of bits. + * Peer wants us to use a different number of bits + * or a different version. */ - if (p[2] < go->bsd_bits) - try.bsd_bits = p[2]; - p += CILEN_BSD; - len -= CILEN_BSD; + if (BSD_VERSION(p[2]) != BSD_CURRENT_VERSION) + try.bsd_compress = 0; + else if (BSD_NBITS(p[2]) < go->bsd_bits) + try.bsd_bits = BSD_NBITS(p[2]); + p += CILEN_BSD_COMPRESS; + len -= CILEN_BSD_COMPRESS; } /* @@ -321,13 +366,13 @@ ccp_rejci(f, p, len) try = *go; - if (go->bsd_compress && len >= CILEN_BSD && p[0] == CI_BSD_COMPRESS - && p[1] == CILEN_BSD) { - if (p[2] != go->bsd_bits) + if (go->bsd_compress && len >= CILEN_BSD_COMPRESS + && p[0] == CI_BSD_COMPRESS && p[1] == CILEN_BSD_COMPRESS) { + if (p[2] != BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits)) return 0; try.bsd_compress = 0; - p += CILEN_BSD; - len -= CILEN_BSD; + p += CILEN_BSD_COMPRESS; + len -= CILEN_BSD_COMPRESS; } if (len != 0) @@ -353,12 +398,12 @@ ccp_reqci(f, p, lenp, dont_nak) { int ret, newret; u_char *p0, *retp; - int len, clen, type; + int len, clen, type, nb; ccp_options *ho = &ccp_hisoptions[f->unit]; ccp_options *ao = &ccp_allowoptions[f->unit]; ret = CONFACK; - p0 = p; + retp = p0 = p; len = *lenp; memset(ho, 0, sizeof(ccp_options)); @@ -376,19 +421,28 @@ ccp_reqci(f, p, lenp, dont_nak) switch (type) { case CI_BSD_COMPRESS: - if (!ao->bsd_compress || clen != CILEN_BSD) { + if (!ao->bsd_compress || clen != CILEN_BSD_COMPRESS) { newret = CONFREJ; break; } ho->bsd_compress = 1; - ho->bsd_bits = p[2]; - if (ho->bsd_bits < MIN_BSD_BITS - || ho->bsd_bits > ao->bsd_bits) { + ho->bsd_bits = nb = BSD_NBITS(p[2]); + if (BSD_VERSION(p[2]) != BSD_CURRENT_VERSION + || nb > ao->bsd_bits) { newret = CONFNAK; - if (!dont_nak) - p[2] = (ho->bsd_bits < MIN_BSD_BITS? MIN_BSD_BITS: - ao->bsd_bits); + nb = ao->bsd_bits; + } else if (nb < BSD_MIN_BITS) { + newret = CONFREJ; + } else if (!ccp_test(f->unit, p, CILEN_BSD_COMPRESS, 1)) { + if (nb > BSD_MIN_BITS) { + --nb; + newret = CONFNAK; + } else + newret = CONFREJ; + } + if (newret == CONFNAK && !dont_nak) { + p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, nb); } break; @@ -398,12 +452,13 @@ ccp_reqci(f, p, lenp, dont_nak) } } + if (newret == CONFNAK && dont_nak) + newret = CONFREJ; if (!(newret == CONFACK || newret == CONFNAK && ret == CONFREJ)) { /* we're returning this option */ - if (newret != ret) { + if (newret == CONFREJ && ret == CONFNAK) retp = p0; - ret = newret; - } + ret = newret; if (p != retp) BCOPY(p, retp, clen); retp += clen; @@ -425,7 +480,14 @@ static void ccp_up(f) fsm *f; { + ccp_options *go = &ccp_gotoptions[f->unit]; + ccp_options *ho = &ccp_hisoptions[f->unit]; + ccp_flags_set(f->unit, 1, 1); + if (go->bsd_compress || ho->bsd_compress) + syslog(LOG_NOTICE, "%s enabled", + go->bsd_compress? ho->bsd_compress? "Compression": + "Receive compression": "Transmit compression"); } /* @@ -455,7 +517,7 @@ int ccp_printpkt(p, plen, printer, arg) u_char *p; int plen; - void (*printer) __ARGS((void *, char *, ...)); + void (*printer) __P((void *, char *, ...)); void *arg; { u_char *p0, *optend; @@ -496,9 +558,10 @@ ccp_printpkt(p, plen, printer, arg) optend = p + optlen; switch (code) { case CI_BSD_COMPRESS: - if (optlen >= CILEN_BSD) { - printer(arg, "bsd %d", p[2]); - p += CILEN_BSD; + if (optlen >= CILEN_BSD_COMPRESS) { + printer(arg, "bsd v%d %d", BSD_VERSION(p[2]), + BSD_NBITS(p[2])); + p += CILEN_BSD_COMPRESS; } break; } @@ -517,8 +580,16 @@ ccp_printpkt(p, plen, printer, arg) } /* - * We have received a packet that the decompressor failed to decompress. - * Issue a reset-req (if we haven't issued one recently). + * We have received a packet that the decompressor failed to + * decompress. Here we would expect to issue a reset-request, but + * Motorola has a patent on resetting the compressor as a result of + * detecting an error in the decompressed data after decompression. + * (See US patent 5,130,993; international patent publication number + * WO 91/10289; Australian patent 73296/91.) + * + * So we ask the kernel whether the error was detected after + * decompression; if it was, we take CCP down, thus disabling + * compression :-(, otherwise we issue the reset-request. */ void ccp_datainput(unit, pkt, len) @@ -530,12 +601,25 @@ ccp_datainput(unit, pkt, len) f = &ccp_fsm[unit]; if (f->state == OPENED) { - if (!(ccp_localstate[unit] & RACK_PENDING)) { - fsm_sdata(f, RESETREQ, f->reqid = ++f->id, NULL, 0); - TIMEOUT(ccp_rack_timeout, (caddr_t) f, RACKTIMEOUT); - ccp_localstate[unit] |= RACK_PENDING; - } else - ccp_localstate[unit] |= RREQ_REPEAT; + if (ccp_fatal_error(unit)) { + /* + * Disable compression by taking CCP down. + */ + syslog(LOG_ERR, "Lost compression sync: disabling compression"); + ccp_close(unit); + } else { + /* + * Send a reset-request to reset the peer's compressor. + * We don't do that if we are still waiting for an + * acknowledgement to a previous reset-request. + */ + if (!(ccp_localstate[f->unit] & RACK_PENDING)) { + fsm_sdata(f, CCP_RESETREQ, f->reqid = ++f->id, NULL, 0); + TIMEOUT(ccp_rack_timeout, (caddr_t) f, RACKTIMEOUT); + ccp_localstate[f->unit] |= RACK_PENDING; + } else + ccp_localstate[f->unit] |= RREQ_REPEAT; + } } } @@ -549,7 +633,7 @@ ccp_rack_timeout(arg) fsm *f = (fsm *) arg; if (f->state == OPENED && ccp_localstate[f->unit] & RREQ_REPEAT) { - fsm_sdata(f, RESETREQ, f->reqid, NULL, 0); + fsm_sdata(f, CCP_RESETREQ, f->reqid, NULL, 0); TIMEOUT(ccp_rack_timeout, (caddr_t) f, RACKTIMEOUT); ccp_localstate[f->unit] &= ~RREQ_REPEAT; } else