/*
* ccp.c - PPP Compression Control Protocol.
*
- * Copyright (c) 1994 The Australian National University.
- * All rights reserved.
+ * Copyright (c) 1994-2002 Paul Mackerras. 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.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
*
- * 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.
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
*
- * 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.
+ * 2. The name(s) of the authors of this software must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission.
+ *
+ * 3. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by Paul Mackerras
+ * <paulus@samba.org>".
+ *
+ * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifndef lint
-static char rcsid[] = "$Id: ccp.c,v 1.20 1997/04/30 05:50:40 paulus Exp $";
+#ifdef HAVE_CONFIG_H
+#include "config.h"
#endif
+#define RCSID "$Id: ccp.c,v 1.50 2005/06/26 19:34:41 carlsonj Exp $"
+
+#include <stdlib.h>
#include <string.h>
-#include <syslog.h>
-#include <sys/ioctl.h>
-#include <sys/types.h>
-#include <net/ppp_defs.h>
+#if defined(SOL2)
#include <net/ppp-comp.h>
+#else
+#include <linux/ppp-comp.h>
+#endif
-#include "pppd.h"
+#include "pppd-private.h"
+#include "options.h"
#include "fsm.h"
#include "ccp.h"
+#include "chap_ms.h"
+#include "mppe.h"
+#include "lcp.h" /* lcp_close(), lcp_fsm */
+
+
+/*
+ * Unfortunately there is a bug in zlib which means that using a
+ * size of 8 (window size = 256) for Deflate compression will cause
+ * buffer overruns and kernel crashes in the deflate module.
+ * Until this is fixed we only accept sizes in the range 9 .. 15.
+ * Thanks to James Carlson for pointing this out.
+ */
+#define DEFLATE_MIN_WORKS 9
+
+/*
+ * Command-line options.
+ */
+static int setbsdcomp (char **);
+static int setdeflate (char **);
+static char bsd_value[8];
+static char deflate_value[8];
+
+/*
+ * Option variables.
+ */
+#ifdef PPP_WITH_MPPE
+bool refuse_mppe_stateful = 1; /* Allow stateful mode? */
+#endif
+
+static struct option ccp_option_list[] = {
+ { "noccp", o_bool, &ccp_protent.enabled_flag,
+ "Disable CCP negotiation" },
+ { "-ccp", o_bool, &ccp_protent.enabled_flag,
+ "Disable CCP negotiation", OPT_ALIAS },
+
+ { "bsdcomp", o_special, (void *)setbsdcomp,
+ "Request BSD-Compress packet compression",
+ OPT_PRIO | OPT_A2STRVAL | OPT_STATIC, bsd_value },
+ { "nobsdcomp", o_bool, &ccp_wantoptions[0].bsd_compress,
+ "don't allow BSD-Compress", OPT_PRIOSUB | OPT_A2CLR,
+ &ccp_allowoptions[0].bsd_compress },
+ { "-bsdcomp", o_bool, &ccp_wantoptions[0].bsd_compress,
+ "don't allow BSD-Compress", OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLR,
+ &ccp_allowoptions[0].bsd_compress },
+
+ { "deflate", o_special, (void *)setdeflate,
+ "request Deflate compression",
+ OPT_PRIO | OPT_A2STRVAL | OPT_STATIC, deflate_value },
+ { "nodeflate", o_bool, &ccp_wantoptions[0].deflate,
+ "don't allow Deflate compression", OPT_PRIOSUB | OPT_A2CLR,
+ &ccp_allowoptions[0].deflate },
+ { "-deflate", o_bool, &ccp_wantoptions[0].deflate,
+ "don't allow Deflate compression", OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLR,
+ &ccp_allowoptions[0].deflate },
+
+ { "nodeflatedraft", o_bool, &ccp_wantoptions[0].deflate_draft,
+ "don't use draft deflate #", OPT_A2COPY,
+ &ccp_allowoptions[0].deflate_draft },
+
+ { "predictor1", o_bool, &ccp_wantoptions[0].predictor_1,
+ "request Predictor-1", OPT_PRIO | 1 },
+ { "nopredictor1", o_bool, &ccp_wantoptions[0].predictor_1,
+ "don't allow Predictor-1", OPT_PRIOSUB | OPT_A2CLR,
+ &ccp_allowoptions[0].predictor_1 },
+ { "-predictor1", o_bool, &ccp_wantoptions[0].predictor_1,
+ "don't allow Predictor-1", OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLR,
+ &ccp_allowoptions[0].predictor_1 },
+
+#ifdef PPP_WITH_MPPE
+ /* MPPE options are symmetrical ... we only set wantoptions here */
+ { "require-mppe", o_bool, &ccp_wantoptions[0].mppe,
+ "require MPPE encryption",
+ OPT_PRIO | MPPE_OPT_40 | MPPE_OPT_128 },
+ { "+mppe", o_bool, &ccp_wantoptions[0].mppe,
+ "require MPPE encryption",
+ OPT_ALIAS | OPT_PRIO | MPPE_OPT_40 | MPPE_OPT_128 },
+ { "nomppe", o_bool, &ccp_wantoptions[0].mppe,
+ "don't allow MPPE encryption", OPT_PRIO },
+ { "-mppe", o_bool, &ccp_wantoptions[0].mppe,
+ "don't allow MPPE encryption", OPT_ALIAS | OPT_PRIO },
+
+ /* We use ccp_allowoptions[0].mppe as a junk var ... it is reset later */
+ { "require-mppe-40", o_bool, &ccp_allowoptions[0].mppe,
+ "require MPPE 40-bit encryption", OPT_PRIO | OPT_A2OR | MPPE_OPT_40,
+ &ccp_wantoptions[0].mppe },
+ { "+mppe-40", o_bool, &ccp_allowoptions[0].mppe,
+ "require MPPE 40-bit encryption", OPT_PRIO | OPT_A2OR | MPPE_OPT_40,
+ &ccp_wantoptions[0].mppe },
+ { "nomppe-40", o_bool, &ccp_allowoptions[0].mppe,
+ "don't allow MPPE 40-bit encryption",
+ OPT_PRIOSUB | OPT_A2CLRB | MPPE_OPT_40, &ccp_wantoptions[0].mppe },
+ { "-mppe-40", o_bool, &ccp_allowoptions[0].mppe,
+ "don't allow MPPE 40-bit encryption",
+ OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLRB | MPPE_OPT_40,
+ &ccp_wantoptions[0].mppe },
+
+ { "require-mppe-128", o_bool, &ccp_allowoptions[0].mppe,
+ "require MPPE 128-bit encryption", OPT_PRIO | OPT_A2OR | MPPE_OPT_128,
+ &ccp_wantoptions[0].mppe },
+ { "+mppe-128", o_bool, &ccp_allowoptions[0].mppe,
+ "require MPPE 128-bit encryption",
+ OPT_ALIAS | OPT_PRIO | OPT_A2OR | MPPE_OPT_128,
+ &ccp_wantoptions[0].mppe },
+ { "nomppe-128", o_bool, &ccp_allowoptions[0].mppe,
+ "don't allow MPPE 128-bit encryption",
+ OPT_PRIOSUB | OPT_A2CLRB | MPPE_OPT_128, &ccp_wantoptions[0].mppe },
+ { "-mppe-128", o_bool, &ccp_allowoptions[0].mppe,
+ "don't allow MPPE 128-bit encryption",
+ OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLRB | MPPE_OPT_128,
+ &ccp_wantoptions[0].mppe },
+
+ /* strange one; we always request stateless, but will we allow stateful? */
+ { "mppe-stateful", o_bool, &refuse_mppe_stateful,
+ "allow MPPE stateful mode", OPT_PRIO },
+ { "nomppe-stateful", o_bool, &refuse_mppe_stateful,
+ "disallow MPPE stateful mode", OPT_PRIO | 1 },
+#endif /* MPPE */
+
+ { NULL }
+};
+
/*
* Protocol entry points from main code.
*/
-static void ccp_init __P((int unit));
-static void ccp_open __P((int unit));
-static void ccp_close __P((int unit, char *));
-static void ccp_lowerup __P((int unit));
-static void ccp_lowerdown __P((int));
-static void ccp_input __P((int unit, u_char *pkt, int len));
-static void ccp_protrej __P((int unit));
-static int ccp_printpkt __P((u_char *pkt, int len,
- void (*printer) __P((void *, char *, ...)),
- void *arg));
-static void ccp_datainput __P((int unit, u_char *pkt, int len));
+static void ccp_init (int unit);
+static void ccp_open (int unit);
+static void ccp_close (int unit, char *);
+static void ccp_lowerup (int unit);
+static void ccp_lowerdown (int);
+static void ccp_input (int unit, u_char *pkt, int len);
+static void ccp_protrej (int unit);
+static int ccp_printpkt (u_char *pkt, int len,
+ void (*printer)(void *, char *, ...),
+ void *arg);
+static void ccp_datainput (int unit, u_char *pkt, int len);
struct protent ccp_protent = {
PPP_CCP,
ccp_datainput,
1,
"CCP",
+ "Compressed",
+ ccp_option_list,
NULL,
NULL,
NULL
/*
* Callbacks for fsm code.
*/
-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((void *));
-static char *method_name __P((ccp_options *, ccp_options *));
+static void ccp_resetci (fsm *);
+static int ccp_cilen (fsm *);
+static void ccp_addci (fsm *, u_char *, int *);
+static int ccp_ackci (fsm *, u_char *, int);
+static int ccp_nakci (fsm *, u_char *, int, int);
+static int ccp_rejci (fsm *, u_char *, int);
+static int ccp_reqci (fsm *, u_char *, int *, int);
+static void ccp_up (fsm *);
+static void ccp_down (fsm *);
+static int ccp_extcode (fsm *, int, int, u_char *, int);
+static void ccp_rack_timeout (void *);
+static char *method_name (ccp_options *, ccp_options *);
static fsm_callbacks ccp_callbacks = {
ccp_resetci,
* Do we want / did we get any compression?
*/
#define ANY_COMPRESS(opt) ((opt).deflate || (opt).bsd_compress \
- || (opt).predictor_1 || (opt).predictor_2)
+ || (opt).predictor_1 || (opt).predictor_2 \
+ || (opt).mppe)
/*
* Local state (mainly for handling reset-reqs and reset-acks).
static int all_rejected[NUM_PPP]; /* we rejected all peer's options */
+/*
+ * Option parsing.
+ */
+static int
+setbsdcomp(char **argv)
+{
+ int rbits, abits;
+ char *str, *endp;
+
+ str = *argv;
+ abits = rbits = strtol(str, &endp, 0);
+ if (endp != str && *endp == ',') {
+ str = endp + 1;
+ abits = strtol(str, &endp, 0);
+ }
+ if (*endp != 0 || endp == str) {
+ ppp_option_error("invalid parameter '%s' for bsdcomp option", *argv);
+ return 0;
+ }
+ if ((rbits != 0 && (rbits < BSD_MIN_BITS || rbits > BSD_MAX_BITS))
+ || (abits != 0 && (abits < BSD_MIN_BITS || abits > BSD_MAX_BITS))) {
+ ppp_option_error("bsdcomp option values must be 0 or %d .. %d",
+ BSD_MIN_BITS, BSD_MAX_BITS);
+ return 0;
+ }
+ if (rbits > 0) {
+ ccp_wantoptions[0].bsd_compress = 1;
+ ccp_wantoptions[0].bsd_bits = rbits;
+ } else
+ ccp_wantoptions[0].bsd_compress = 0;
+ if (abits > 0) {
+ ccp_allowoptions[0].bsd_compress = 1;
+ ccp_allowoptions[0].bsd_bits = abits;
+ } else
+ ccp_allowoptions[0].bsd_compress = 0;
+ slprintf(bsd_value, sizeof(bsd_value),
+ rbits == abits? "%d": "%d,%d", rbits, abits);
+
+ return 1;
+}
+
+static int
+setdeflate(char **argv)
+{
+ int rbits, abits;
+ char *str, *endp;
+
+ str = *argv;
+ abits = rbits = strtol(str, &endp, 0);
+ if (endp != str && *endp == ',') {
+ str = endp + 1;
+ abits = strtol(str, &endp, 0);
+ }
+ if (*endp != 0 || endp == str) {
+ ppp_option_error("invalid parameter '%s' for deflate option", *argv);
+ return 0;
+ }
+ if ((rbits != 0 && (rbits < DEFLATE_MIN_SIZE || rbits > DEFLATE_MAX_SIZE))
+ || (abits != 0 && (abits < DEFLATE_MIN_SIZE
+ || abits > DEFLATE_MAX_SIZE))) {
+ ppp_option_error("deflate option values must be 0 or %d .. %d",
+ DEFLATE_MIN_SIZE, DEFLATE_MAX_SIZE);
+ return 0;
+ }
+ if (rbits == DEFLATE_MIN_SIZE || abits == DEFLATE_MIN_SIZE) {
+ if (rbits == DEFLATE_MIN_SIZE)
+ rbits = DEFLATE_MIN_WORKS;
+ if (abits == DEFLATE_MIN_SIZE)
+ abits = DEFLATE_MIN_WORKS;
+ warn("deflate option value of %d changed to %d to avoid zlib bug",
+ DEFLATE_MIN_SIZE, DEFLATE_MIN_WORKS);
+ }
+ if (rbits > 0) {
+ ccp_wantoptions[0].deflate = 1;
+ ccp_wantoptions[0].deflate_size = rbits;
+ } else
+ ccp_wantoptions[0].deflate = 0;
+ if (abits > 0) {
+ ccp_allowoptions[0].deflate = 1;
+ ccp_allowoptions[0].deflate_size = abits;
+ } else
+ ccp_allowoptions[0].deflate = 0;
+ slprintf(deflate_value, sizeof(deflate_value),
+ rbits == abits? "%d": "%d,%d", rbits, abits);
+
+ return 1;
+}
+
/*
* ccp_init - initialize CCP.
*/
static void
-ccp_init(unit)
- int unit;
+ccp_init(int unit)
{
fsm *f = &ccp_fsm[unit];
ccp_wantoptions[0].deflate = 1;
ccp_wantoptions[0].deflate_size = DEFLATE_MAX_SIZE;
+ ccp_wantoptions[0].deflate_correct = 1;
+ ccp_wantoptions[0].deflate_draft = 1;
ccp_allowoptions[0].deflate = 1;
ccp_allowoptions[0].deflate_size = DEFLATE_MAX_SIZE;
+ ccp_allowoptions[0].deflate_correct = 1;
+ ccp_allowoptions[0].deflate_draft = 1;
ccp_wantoptions[0].bsd_compress = 1;
ccp_wantoptions[0].bsd_bits = BSD_MAX_BITS;
* ccp_open - CCP is allowed to come up.
*/
static void
-ccp_open(unit)
- int unit;
+ccp_open(int unit)
{
fsm *f = &ccp_fsm[unit];
* ccp_close - Terminate CCP.
*/
static void
-ccp_close(unit, reason)
- int unit;
- char *reason;
+ccp_close(int unit, char *reason)
{
ccp_flags_set(unit, 0, 0);
fsm_close(&ccp_fsm[unit], reason);
* ccp_lowerup - we may now transmit CCP packets.
*/
static void
-ccp_lowerup(unit)
- int unit;
+ccp_lowerup(int unit)
{
fsm_lowerup(&ccp_fsm[unit]);
}
* ccp_lowerdown - we may not transmit CCP packets.
*/
static void
-ccp_lowerdown(unit)
- int unit;
+ccp_lowerdown(int unit)
{
fsm_lowerdown(&ccp_fsm[unit]);
}
* ccp_input - process a received CCP packet.
*/
static void
-ccp_input(unit, p, len)
- int unit;
- u_char *p;
- int len;
+ccp_input(int unit, u_char *p, int len)
{
fsm *f = &ccp_fsm[unit];
int oldstate;
*/
oldstate = f->state;
fsm_input(f, p, len);
- if (oldstate == OPENED && p[0] == TERMREQ && f->state != OPENED)
- syslog(LOG_NOTICE, "Compression disabled by peer.");
+ if (oldstate == OPENED && p[0] == TERMREQ && f->state != OPENED) {
+ notice("Compression disabled by peer.");
+#ifdef PPP_WITH_MPPE
+ if (ccp_gotoptions[unit].mppe) {
+ error("MPPE disabled, closing LCP");
+ lcp_close(unit, "MPPE disabled by peer");
+ }
+#endif
+ }
/*
* If we get a terminate-ack and we're not asking for compression,
* Handle a CCP-specific code.
*/
static int
-ccp_extcode(f, code, id, p, len)
- fsm *f;
- int code, id;
- u_char *p;
- int len;
+ccp_extcode(fsm *f, int code, int id, u_char *p, int len)
{
switch (code) {
case CCP_RESETREQ:
* ccp_protrej - peer doesn't talk CCP.
*/
static void
-ccp_protrej(unit)
- int unit;
+ccp_protrej(int unit)
{
ccp_flags_set(unit, 0, 0);
fsm_lowerdown(&ccp_fsm[unit]);
+
+#ifdef PPP_WITH_MPPE
+ if (ccp_gotoptions[unit].mppe) {
+ error("MPPE required but peer negotiation failed");
+ lcp_close(unit, "MPPE required but peer negotiation failed");
+ }
+#endif
+
}
/*
* ccp_resetci - initialize at start of negotiation.
*/
static void
-ccp_resetci(f)
- fsm *f;
+ccp_resetci(fsm *f)
{
ccp_options *go = &ccp_gotoptions[f->unit];
- u_char opt_buf[16];
+ u_char opt_buf[CCP_MAX_OPTION_LENGTH];
*go = ccp_wantoptions[f->unit];
all_rejected[f->unit] = 0;
+#ifdef PPP_WITH_MPPE
+ if (go->mppe) {
+ ccp_options *ao = &ccp_allowoptions[f->unit];
+ int auth_mschap_bits = auth_done[f->unit];
+#ifdef PPP_WITH_EAPTLS
+ int auth_eap_bits = auth_done[f->unit];
+#endif
+ int numbits;
+
+ /*
+ * Start with a basic sanity check: mschap[v2] auth must be in
+ * exactly one direction. RFC 3079 says that the keys are
+ * 'derived from the credentials of the peer that initiated the call',
+ * however the PPP protocol doesn't have such a concept, and pppd
+ * cannot get this info externally. Instead we do the best we can.
+ * NB: If MPPE is required, all other compression opts are invalid.
+ * So, we return right away if we can't do it.
+ */
+
+ /* Leave only the mschap auth bits set */
+ auth_mschap_bits &= (CHAP_MS_WITHPEER | CHAP_MS_PEER |
+ CHAP_MS2_WITHPEER | CHAP_MS2_PEER);
+ /* Count the mschap auths */
+ auth_mschap_bits >>= CHAP_MS_SHIFT;
+ numbits = 0;
+ do {
+ numbits += auth_mschap_bits & 1;
+ auth_mschap_bits >>= 1;
+ } while (auth_mschap_bits);
+ if (numbits > 1) {
+ error("MPPE required, but auth done in both directions.");
+ lcp_close(f->unit, "MPPE required but not available");
+ return;
+ }
+
+#ifdef PPP_WITH_EAPTLS
+ /*
+ * MPPE is also possible in combination with EAP-TLS.
+ * It is not possible to detect if we're doing EAP or EAP-TLS
+ * at this stage, hence we accept all forms of EAP. If TLS is
+ * not used then the MPPE keys will not be derived anyway.
+ */
+ /* Leave only the eap auth bits set */
+ auth_eap_bits &= (EAP_WITHPEER | EAP_PEER );
+
+ if ((numbits == 0) && (auth_eap_bits == 0)) {
+ error("MPPE required, but MS-CHAP[v2] nor EAP-TLS auth are performed.");
+#else
+ if (!numbits) {
+ error("MPPE required, but MS-CHAP[v2] auth not performed.");
+#endif
+ lcp_close(f->unit, "MPPE required but not available");
+ return;
+ }
+
+ /* A plugin (eg radius) may not have obtained key material. */
+ if (!mppe_keys_isset()) {
+ error("MPPE required, but keys are not available. "
+ "Possible plugin problem?");
+ lcp_close(f->unit, "MPPE required but not available");
+ return;
+ }
+
+ /* LM auth not supported for MPPE */
+ if (auth_done[f->unit] & (CHAP_MS_WITHPEER | CHAP_MS_PEER)) {
+ /* This might be noise */
+ if (go->mppe & MPPE_OPT_40) {
+ notice("Disabling 40-bit MPPE; MS-CHAP LM not supported");
+ go->mppe &= ~MPPE_OPT_40;
+ ccp_wantoptions[f->unit].mppe &= ~MPPE_OPT_40;
+ }
+ }
+
+ /* Last check: can we actually negotiate something? */
+ if (!(go->mppe & (MPPE_OPT_40 | MPPE_OPT_128))) {
+ /* Could be misconfig, could be 40-bit disabled above. */
+ error("MPPE required, but both 40-bit and 128-bit disabled.");
+ lcp_close(f->unit, "MPPE required but not available");
+ return;
+ }
+
+ /* sync options */
+ ao->mppe = go->mppe;
+ /* MPPE is not compatible with other compression types */
+ ao->bsd_compress = go->bsd_compress = 0;
+ ao->predictor_1 = go->predictor_1 = 0;
+ ao->predictor_2 = go->predictor_2 = 0;
+ ao->deflate = go->deflate = 0;
+ }
+
/*
* Check whether the kernel knows about the various
* compression methods we might request.
*/
+ if (go->mppe) {
+ opt_buf[0] = CI_MPPE;
+ opt_buf[1] = CILEN_MPPE;
+ MPPE_OPTS_TO_CI(go->mppe, &opt_buf[2]);
+ /* Key material unimportant here. */
+ if (ccp_test(f->unit, opt_buf, CILEN_MPPE + MPPE_MAX_KEY_LEN, 0) <= 0) {
+ error("MPPE required, but kernel has no support.");
+ lcp_close(f->unit, "MPPE required but not available");
+ }
+ }
+#endif /* PPP_WITH_MPPE */
if (go->bsd_compress) {
opt_buf[0] = CI_BSD_COMPRESS;
opt_buf[1] = CILEN_BSD_COMPRESS;
go->bsd_compress = 0;
}
if (go->deflate) {
- opt_buf[0] = CI_DEFLATE;
- opt_buf[1] = CILEN_DEFLATE;
- opt_buf[2] = DEFLATE_MAKE_OPT(DEFLATE_MIN_SIZE);
- opt_buf[3] = DEFLATE_CHK_SEQUENCE;
- if (ccp_test(f->unit, opt_buf, CILEN_DEFLATE, 0) <= 0)
+ if (go->deflate_correct) {
+ opt_buf[0] = CI_DEFLATE;
+ opt_buf[1] = CILEN_DEFLATE;
+ opt_buf[2] = DEFLATE_MAKE_OPT(DEFLATE_MIN_WORKS);
+ opt_buf[3] = DEFLATE_CHK_SEQUENCE;
+ if (ccp_test(f->unit, opt_buf, CILEN_DEFLATE, 0) <= 0)
+ go->deflate_correct = 0;
+ }
+ if (go->deflate_draft) {
+ opt_buf[0] = CI_DEFLATE_DRAFT;
+ opt_buf[1] = CILEN_DEFLATE;
+ opt_buf[2] = DEFLATE_MAKE_OPT(DEFLATE_MIN_WORKS);
+ opt_buf[3] = DEFLATE_CHK_SEQUENCE;
+ if (ccp_test(f->unit, opt_buf, CILEN_DEFLATE, 0) <= 0)
+ go->deflate_draft = 0;
+ }
+ if (!go->deflate_correct && !go->deflate_draft)
go->deflate = 0;
}
if (go->predictor_1) {
* ccp_cilen - Return total length of our configuration info.
*/
static int
-ccp_cilen(f)
- fsm *f;
+ ccp_cilen(fsm *f)
{
ccp_options *go = &ccp_gotoptions[f->unit];
return (go->bsd_compress? CILEN_BSD_COMPRESS: 0)
- + (go->deflate? CILEN_DEFLATE: 0)
+ + (go->deflate && go->deflate_correct? CILEN_DEFLATE: 0)
+ + (go->deflate && go->deflate_draft? CILEN_DEFLATE: 0)
+ (go->predictor_1? CILEN_PREDICTOR_1: 0)
- + (go->predictor_2? CILEN_PREDICTOR_2: 0);
+ + (go->predictor_2? CILEN_PREDICTOR_2: 0)
+ + (go->mppe? CILEN_MPPE: 0);
}
/*
* ccp_addci - put our requests in a packet.
*/
static void
-ccp_addci(f, p, lenp)
- fsm *f;
- u_char *p;
- int *lenp;
+ ccp_addci(fsm *f, u_char *p, int *lenp)
{
int res;
ccp_options *go = &ccp_gotoptions[f->unit];
* preference order. Get the kernel to allocate the first one
* in case it gets Acked.
*/
+#ifdef PPP_WITH_MPPE
+ if (go->mppe) {
+ u_char opt_buf[CILEN_MPPE + MPPE_MAX_KEY_LEN];
+
+ p[0] = opt_buf[0] = CI_MPPE;
+ p[1] = opt_buf[1] = CILEN_MPPE;
+ MPPE_OPTS_TO_CI(go->mppe, &p[2]);
+ MPPE_OPTS_TO_CI(go->mppe, &opt_buf[2]);
+ mppe_get_recv_key(&opt_buf[CILEN_MPPE], MPPE_MAX_KEY_LEN);
+ res = ccp_test(f->unit, opt_buf, CILEN_MPPE + MPPE_MAX_KEY_LEN, 0);
+ if (res > 0)
+ p += CILEN_MPPE;
+ else
+ /* This shouldn't happen, we've already tested it! */
+ lcp_close(f->unit, "MPPE required but not available in kernel");
+ }
+#endif
if (go->deflate) {
- p[0] = CI_DEFLATE;
+ p[0] = go->deflate_correct? CI_DEFLATE: CI_DEFLATE_DRAFT;
p[1] = CILEN_DEFLATE;
p[2] = DEFLATE_MAKE_OPT(go->deflate_size);
p[3] = DEFLATE_CHK_SEQUENCE;
- for (;;) {
- res = ccp_test(f->unit, p, CILEN_DEFLATE, 0);
- if (res > 0) {
- p += CILEN_DEFLATE;
- break;
- }
- if (res < 0 || go->deflate_size <= DEFLATE_MIN_SIZE) {
- go->deflate = 0;
- break;
+ if (p != p0) {
+ p += CILEN_DEFLATE;
+ } else {
+ for (;;) {
+ if (go->deflate_size < DEFLATE_MIN_WORKS) {
+ go->deflate = 0;
+ break;
+ }
+ res = ccp_test(f->unit, p, CILEN_DEFLATE, 0);
+ if (res > 0) {
+ p += CILEN_DEFLATE;
+ break;
+ } else if (res < 0) {
+ go->deflate = 0;
+ break;
+ }
+ --go->deflate_size;
+ p[2] = DEFLATE_MAKE_OPT(go->deflate_size);
}
- --go->deflate_size;
- p[2] = DEFLATE_MAKE_OPT(go->deflate_size);
+ }
+ if (p != p0 && go->deflate_correct && go->deflate_draft) {
+ p[0] = CI_DEFLATE_DRAFT;
+ p[1] = CILEN_DEFLATE;
+ p[2] = p[2 - CILEN_DEFLATE];
+ p[3] = DEFLATE_CHK_SEQUENCE;
+ p += CILEN_DEFLATE;
}
}
if (go->bsd_compress) {
p += CILEN_BSD_COMPRESS; /* not the first option */
} else {
for (;;) {
+ if (go->bsd_bits < BSD_MIN_BITS) {
+ go->bsd_compress = 0;
+ break;
+ }
res = ccp_test(f->unit, p, CILEN_BSD_COMPRESS, 0);
if (res > 0) {
p += CILEN_BSD_COMPRESS;
break;
- }
- if (res < 0 || go->bsd_bits <= BSD_MIN_BITS) {
+ } else if (res < 0) {
go->bsd_compress = 0;
break;
}
* 1 iff the packet was OK.
*/
static int
-ccp_ackci(f, p, len)
- fsm *f;
- u_char *p;
- int len;
+ ccp_ackci(fsm *f, u_char *p, int len)
{
ccp_options *go = &ccp_gotoptions[f->unit];
u_char *p0 = p;
+#ifdef PPP_WITH_MPPE
+ if (go->mppe) {
+ u_char opt_buf[CILEN_MPPE];
+
+ opt_buf[0] = CI_MPPE;
+ opt_buf[1] = CILEN_MPPE;
+ MPPE_OPTS_TO_CI(go->mppe, &opt_buf[2]);
+ if (len < CILEN_MPPE || memcmp(opt_buf, p, CILEN_MPPE))
+ return 0;
+ p += CILEN_MPPE;
+ len -= CILEN_MPPE;
+ /* XXX Cope with first/fast ack */
+ if (len == 0)
+ return 1;
+ }
+#endif
if (go->deflate) {
if (len < CILEN_DEFLATE
- || p[0] != CI_DEFLATE || p[1] != CILEN_DEFLATE
+ || p[0] != (go->deflate_correct? CI_DEFLATE: CI_DEFLATE_DRAFT)
+ || p[1] != CILEN_DEFLATE
|| p[2] != DEFLATE_MAKE_OPT(go->deflate_size)
|| p[3] != DEFLATE_CHK_SEQUENCE)
return 0;
/* XXX Cope with first/fast ack */
if (len == 0)
return 1;
+ if (go->deflate_correct && go->deflate_draft) {
+ if (len < CILEN_DEFLATE
+ || p[0] != CI_DEFLATE_DRAFT
+ || p[1] != CILEN_DEFLATE
+ || p[2] != DEFLATE_MAKE_OPT(go->deflate_size)
+ || p[3] != DEFLATE_CHK_SEQUENCE)
+ return 0;
+ p += CILEN_DEFLATE;
+ len -= CILEN_DEFLATE;
+ }
}
if (go->bsd_compress) {
if (len < CILEN_BSD_COMPRESS
* Returns 1 iff the nak was OK.
*/
static int
-ccp_nakci(f, p, len)
- fsm *f;
- u_char *p;
- int len;
+ ccp_nakci(fsm *f, u_char *p, int len, int treat_as_reject)
{
ccp_options *go = &ccp_gotoptions[f->unit];
ccp_options no; /* options we've seen already */
memset(&no, 0, sizeof(no));
try = *go;
+#ifdef PPP_WITH_MPPE
+ if (go->mppe && len >= CILEN_MPPE
+ && p[0] == CI_MPPE && p[1] == CILEN_MPPE) {
+ no.mppe = 1;
+ /*
+ * Peer wants us to use a different strength or other setting.
+ * Fail if we aren't willing to use his suggestion.
+ */
+ MPPE_CI_TO_OPTS(&p[2], try.mppe);
+ if ((try.mppe & MPPE_OPT_STATEFUL) && refuse_mppe_stateful) {
+ error("Refusing MPPE stateful mode offered by peer");
+ try.mppe = 0;
+ } else if (((go->mppe | MPPE_OPT_STATEFUL) & try.mppe) != try.mppe) {
+ /* Peer must have set options we didn't request (suggest) */
+ try.mppe = 0;
+ }
+
+ if (!try.mppe) {
+ error("MPPE required but peer negotiation failed");
+ lcp_close(f->unit, "MPPE required but peer negotiation failed");
+ }
+ }
+#endif /* PPP_WITH_MPPE */
if (go->deflate && len >= CILEN_DEFLATE
- && p[0] == CI_DEFLATE && p[1] == CILEN_DEFLATE) {
+ && p[0] == (go->deflate_correct? CI_DEFLATE: CI_DEFLATE_DRAFT)
+ && p[1] == CILEN_DEFLATE) {
no.deflate = 1;
/*
* Peer wants us to use a different code size or something.
* Stop asking for Deflate if we don't understand his suggestion.
*/
if (DEFLATE_METHOD(p[2]) != DEFLATE_METHOD_VAL
- || DEFLATE_SIZE(p[2]) < DEFLATE_MIN_SIZE
+ || DEFLATE_SIZE(p[2]) < DEFLATE_MIN_WORKS
|| p[3] != DEFLATE_CHK_SEQUENCE)
try.deflate = 0;
else if (DEFLATE_SIZE(p[2]) < go->deflate_size)
- go->deflate_size = DEFLATE_SIZE(p[2]);
+ try.deflate_size = DEFLATE_SIZE(p[2]);
p += CILEN_DEFLATE;
len -= CILEN_DEFLATE;
+ if (go->deflate_correct && go->deflate_draft
+ && len >= CILEN_DEFLATE && p[0] == CI_DEFLATE_DRAFT
+ && p[1] == CILEN_DEFLATE) {
+ p += CILEN_DEFLATE;
+ len -= CILEN_DEFLATE;
+ }
}
if (go->bsd_compress && len >= CILEN_BSD_COMPRESS
/*
* Predictor-1 and 2 have no options, so they can't be Naked.
*
- * XXX What should we do with any remaining options?
+ * There may be remaining options but we ignore them.
*/
- if (len != 0)
- return 0;
-
if (f->state != OPENED)
*go = try;
return 1;
* ccp_rejci - reject some of our suggested compression methods.
*/
static int
-ccp_rejci(f, p, len)
- fsm *f;
- u_char *p;
- int len;
+ccp_rejci(fsm *f, u_char *p, int len)
{
ccp_options *go = &ccp_gotoptions[f->unit];
ccp_options try; /* options to request next time */
if (len == 0 && all_rejected[f->unit])
return -1;
- if (go->deflate && len >= CILEN_DEFLATE
+#ifdef PPP_WITH_MPPE
+ if (go->mppe && len >= CILEN_MPPE
+ && p[0] == CI_MPPE && p[1] == CILEN_MPPE) {
+ error("MPPE required but peer refused");
+ lcp_close(f->unit, "MPPE required but peer refused");
+ p += CILEN_MPPE;
+ len -= CILEN_MPPE;
+ }
+#endif
+ if (go->deflate_correct && len >= CILEN_DEFLATE
&& p[0] == CI_DEFLATE && p[1] == CILEN_DEFLATE) {
if (p[2] != DEFLATE_MAKE_OPT(go->deflate_size)
|| p[3] != DEFLATE_CHK_SEQUENCE)
return 0; /* Rej is bad */
- try.deflate = 0;
+ try.deflate_correct = 0;
+ p += CILEN_DEFLATE;
+ len -= CILEN_DEFLATE;
+ }
+ if (go->deflate_draft && len >= CILEN_DEFLATE
+ && p[0] == CI_DEFLATE_DRAFT && p[1] == CILEN_DEFLATE) {
+ if (p[2] != DEFLATE_MAKE_OPT(go->deflate_size)
+ || p[3] != DEFLATE_CHK_SEQUENCE)
+ return 0; /* Rej is bad */
+ try.deflate_draft = 0;
p += CILEN_DEFLATE;
len -= CILEN_DEFLATE;
}
+ if (!try.deflate_correct && !try.deflate_draft)
+ try.deflate = 0;
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))
* appropriately.
*/
static int
-ccp_reqci(f, p, lenp, dont_nak)
- fsm *f;
- u_char *p;
- int *lenp;
- int dont_nak;
+ccp_reqci(fsm *f, u_char *p, int *lenp, int dont_nak)
{
int ret, newret, res;
u_char *p0, *retp;
int len, clen, type, nb;
ccp_options *ho = &ccp_hisoptions[f->unit];
ccp_options *ao = &ccp_allowoptions[f->unit];
+#ifdef PPP_WITH_MPPE
+ bool rej_for_ci_mppe = 1; /* Are we rejecting based on a bad/missing */
+ /* CI_MPPE, or due to other options? */
+#endif
ret = CONFACK;
retp = p0 = p;
clen = p[1];
switch (type) {
+#ifdef PPP_WITH_MPPE
+ case CI_MPPE:
+ if (!ao->mppe || clen != CILEN_MPPE) {
+ newret = CONFREJ;
+ break;
+ }
+ MPPE_CI_TO_OPTS(&p[2], ho->mppe);
+
+ /* Nak if anything unsupported or unknown are set. */
+ if (ho->mppe & MPPE_OPT_UNSUPPORTED) {
+ newret = CONFNAK;
+ ho->mppe &= ~MPPE_OPT_UNSUPPORTED;
+ }
+ if (ho->mppe & MPPE_OPT_UNKNOWN) {
+ newret = CONFNAK;
+ ho->mppe &= ~MPPE_OPT_UNKNOWN;
+ }
+
+ /* Check state opt */
+ if (ho->mppe & MPPE_OPT_STATEFUL) {
+ /*
+ * We can Nak and request stateless, but it's a
+ * lot easier to just assume the peer will request
+ * it if he can do it; stateful mode is bad over
+ * the Internet -- which is where we expect MPPE.
+ */
+ if (refuse_mppe_stateful) {
+ error("Refusing MPPE stateful mode offered by peer");
+ newret = CONFREJ;
+ break;
+ }
+ }
+
+ /* Find out which of {S,L} are set. */
+ if ((ho->mppe & MPPE_OPT_128)
+ && (ho->mppe & MPPE_OPT_40)) {
+ /* Both are set, negotiate the strongest. */
+ newret = CONFNAK;
+ if (ao->mppe & MPPE_OPT_128)
+ ho->mppe &= ~MPPE_OPT_40;
+ else if (ao->mppe & MPPE_OPT_40)
+ ho->mppe &= ~MPPE_OPT_128;
+ else {
+ newret = CONFREJ;
+ break;
+ }
+ } else if (ho->mppe & MPPE_OPT_128) {
+ if (!(ao->mppe & MPPE_OPT_128)) {
+ newret = CONFREJ;
+ break;
+ }
+ } else if (ho->mppe & MPPE_OPT_40) {
+ if (!(ao->mppe & MPPE_OPT_40)) {
+ newret = CONFREJ;
+ break;
+ }
+ } else {
+ /* Neither are set. */
+ /* We cannot accept this. */
+ newret = CONFNAK;
+ /* Give the peer our idea of what can be used,
+ so it can choose and confirm */
+ ho->mppe = ao->mppe;
+ }
+
+ /* rebuild the opts */
+ MPPE_OPTS_TO_CI(ho->mppe, &p[2]);
+ if (newret == CONFACK) {
+ u_char opt_buf[CILEN_MPPE + MPPE_MAX_KEY_LEN];
+ int mtu;
+
+ BCOPY(p, opt_buf, CILEN_MPPE);
+ mppe_get_send_key(&opt_buf[CILEN_MPPE], MPPE_MAX_KEY_LEN);
+ if (ccp_test(f->unit, opt_buf,
+ CILEN_MPPE + MPPE_MAX_KEY_LEN, 1) <= 0) {
+ /* This shouldn't happen, we've already tested it! */
+ error("MPPE required, but kernel has no support.");
+ lcp_close(f->unit, "MPPE required but not available");
+ newret = CONFREJ;
+ break;
+ }
+ /*
+ * We need to decrease the interface MTU by MPPE_PAD
+ * because MPPE frames **grow**. The kernel [must]
+ * allocate MPPE_PAD extra bytes in xmit buffers.
+ */
+ mtu = ppp_get_mtu(f->unit);
+ if (mtu)
+ ppp_set_mtu(f->unit, mtu - MPPE_PAD);
+ else
+ newret = CONFREJ;
+ }
+
+ /*
+ * We have accepted MPPE or are willing to negotiate
+ * MPPE parameters. A CONFREJ is due to subsequent
+ * (non-MPPE) processing.
+ */
+ rej_for_ci_mppe = 0;
+ break;
+#endif /* PPP_WITH_MPPE */
case CI_DEFLATE:
- if (!ao->deflate || clen != CILEN_DEFLATE) {
+ case CI_DEFLATE_DRAFT:
+ if (!ao->deflate || clen != CILEN_DEFLATE
+ || (!ao->deflate_correct && type == CI_DEFLATE)
+ || (!ao->deflate_draft && type == CI_DEFLATE_DRAFT)) {
newret = CONFREJ;
break;
}
ho->deflate_size = nb = DEFLATE_SIZE(p[2]);
if (DEFLATE_METHOD(p[2]) != DEFLATE_METHOD_VAL
|| p[3] != DEFLATE_CHK_SEQUENCE
- || nb > ao->deflate_size || nb < DEFLATE_MIN_SIZE) {
+ || nb > ao->deflate_size || nb < DEFLATE_MIN_WORKS) {
newret = CONFNAK;
if (!dont_nak) {
p[2] = DEFLATE_MAKE_OPT(ao->deflate_size);
p[3] = DEFLATE_CHK_SEQUENCE;
- }
- break;
+ /* fall through to test this #bits below */
+ } else
+ break;
}
/*
res = ccp_test(f->unit, p, CILEN_DEFLATE, 1);
if (res > 0)
break; /* it's OK now */
- if (res < 0 || nb == DEFLATE_MIN_SIZE || dont_nak) {
+ if (res < 0 || nb == DEFLATE_MIN_WORKS || dont_nak) {
newret = CONFREJ;
p[2] = DEFLATE_MAKE_OPT(ho->deflate_size);
break;
if (BSD_VERSION(p[2]) != BSD_CURRENT_VERSION
|| nb > ao->bsd_bits || nb < BSD_MIN_BITS) {
newret = CONFNAK;
- if (!dont_nak)
+ if (!dont_nak) {
p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, ao->bsd_bits);
- break;
+ /* fall through to test this #bits below */
+ } else
+ break;
}
/*
else
*lenp = retp - p0;
}
+#ifdef PPP_WITH_MPPE
+ if (ret == CONFREJ && ao->mppe && rej_for_ci_mppe) {
+ error("MPPE required but peer negotiation failed");
+ lcp_close(f->unit, "MPPE required but peer negotiation failed");
+ }
+#endif
return ret;
}
* Make a string name for a compression method (or 2).
*/
static char *
-method_name(opt, opt2)
- ccp_options *opt, *opt2;
+method_name(ccp_options *opt, ccp_options *opt2)
{
static char result[64];
if (!ANY_COMPRESS(*opt))
return "(none)";
switch (opt->method) {
+#ifdef PPP_WITH_MPPE
+ case CI_MPPE:
+ {
+ char *p = result;
+ char *q = result + sizeof(result); /* 1 past result */
+
+ slprintf(p, q - p, "MPPE ");
+ p += 5;
+ if (opt->mppe & MPPE_OPT_128) {
+ slprintf(p, q - p, "128-bit ");
+ p += 8;
+ }
+ if (opt->mppe & MPPE_OPT_40) {
+ slprintf(p, q - p, "40-bit ");
+ p += 7;
+ }
+ if (opt->mppe & MPPE_OPT_STATEFUL)
+ slprintf(p, q - p, "stateful");
+ else
+ slprintf(p, q - p, "stateless");
+
+ break;
+ }
+#endif
case CI_DEFLATE:
+ case CI_DEFLATE_DRAFT:
if (opt2 != NULL && opt2->deflate_size != opt->deflate_size)
- sprintf(result, "Deflate (%d/%d)", opt->deflate_size,
- opt2->deflate_size);
+ slprintf(result, sizeof(result), "Deflate%s (%d/%d)",
+ (opt->method == CI_DEFLATE_DRAFT? "(old#)": ""),
+ opt->deflate_size, opt2->deflate_size);
else
- sprintf(result, "Deflate (%d)", opt->deflate_size);
+ slprintf(result, sizeof(result), "Deflate%s (%d)",
+ (opt->method == CI_DEFLATE_DRAFT? "(old#)": ""),
+ opt->deflate_size);
break;
case CI_BSD_COMPRESS:
if (opt2 != NULL && opt2->bsd_bits != opt->bsd_bits)
- sprintf(result, "BSD-Compress (%d/%d)", opt->bsd_bits,
- opt2->bsd_bits);
+ slprintf(result, sizeof(result), "BSD-Compress (%d/%d)",
+ opt->bsd_bits, opt2->bsd_bits);
else
- sprintf(result, "BSD-Compress (%d)", opt->bsd_bits);
+ slprintf(result, sizeof(result), "BSD-Compress (%d)",
+ opt->bsd_bits);
break;
case CI_PREDICTOR_1:
return "Predictor 1";
case CI_PREDICTOR_2:
return "Predictor 2";
default:
- sprintf(result, "Method %d", opt->method);
+ slprintf(result, sizeof(result), "Method %d", opt->method);
}
return result;
}
* CCP has come up - inform the kernel driver and log a message.
*/
static void
-ccp_up(f)
- fsm *f;
+ccp_up(fsm *f)
{
ccp_options *go = &ccp_gotoptions[f->unit];
ccp_options *ho = &ccp_hisoptions[f->unit];
if (ANY_COMPRESS(*go)) {
if (ANY_COMPRESS(*ho)) {
if (go->method == ho->method) {
- syslog(LOG_NOTICE, "%s compression enabled",
- method_name(go, ho));
+ notice("%s compression enabled", method_name(go, ho));
} else {
- strcpy(method1, method_name(go, NULL));
- syslog(LOG_NOTICE, "%s / %s compression enabled",
+ strlcpy(method1, method_name(go, NULL), sizeof(method1));
+ notice("%s / %s compression enabled",
method1, method_name(ho, NULL));
}
} else
- syslog(LOG_NOTICE, "%s receive compression enabled",
- method_name(go, NULL));
+ notice("%s receive compression enabled", method_name(go, NULL));
} else if (ANY_COMPRESS(*ho))
- syslog(LOG_NOTICE, "%s transmit compression enabled",
- method_name(ho, NULL));
+ notice("%s transmit compression enabled", method_name(ho, NULL));
+#ifdef PPP_WITH_MPPE
+ if (go->mppe) {
+ mppe_clear_keys();
+ continue_networks(f->unit); /* Bring up IP et al */
+ }
+#endif
}
/*
* CCP has gone down - inform the kernel driver.
*/
static void
-ccp_down(f)
- fsm *f;
+ccp_down(fsm *f)
{
if (ccp_localstate[f->unit] & RACK_PENDING)
UNTIMEOUT(ccp_rack_timeout, f);
ccp_localstate[f->unit] = 0;
ccp_flags_set(f->unit, 1, 0);
+#ifdef PPP_WITH_MPPE
+ if (ccp_gotoptions[f->unit].mppe) {
+ ccp_gotoptions[f->unit].mppe = 0;
+ if (lcp_fsm[f->unit].state == OPENED) {
+ /* If LCP is not already going down, make sure it does. */
+ error("MPPE disabled");
+ lcp_close(f->unit, "MPPE disabled");
+ }
+ }
+#endif
}
/*
};
static int
-ccp_printpkt(p, plen, printer, arg)
- u_char *p;
- int plen;
- void (*printer) __P((void *, char *, ...));
- void *arg;
+ccp_printpkt(u_char *p, int plen,
+ void (*printer) (void *, char *, ...), void *arg)
{
u_char *p0, *optend;
int code, id, len;
len -= optlen;
optend = p + optlen;
switch (code) {
+#ifdef PPP_WITH_MPPE
+ case CI_MPPE:
+ if (optlen >= CILEN_MPPE) {
+ u_char mppe_opts;
+
+ MPPE_CI_TO_OPTS(&p[2], mppe_opts);
+ printer(arg, "mppe %s %s %s %s %s %s%s",
+ (p[2] & MPPE_H_BIT)? "+H": "-H",
+ (p[5] & MPPE_M_BIT)? "+M": "-M",
+ (p[5] & MPPE_S_BIT)? "+S": "-S",
+ (p[5] & MPPE_L_BIT)? "+L": "-L",
+ (p[5] & MPPE_D_BIT)? "+D": "-D",
+ (p[5] & MPPE_C_BIT)? "+C": "-C",
+ (mppe_opts & MPPE_OPT_UNKNOWN)? " +U": "");
+ if (mppe_opts & MPPE_OPT_UNKNOWN)
+ printer(arg, " (%.2x %.2x %.2x %.2x)",
+ p[2], p[3], p[4], p[5]);
+ p += CILEN_MPPE;
+ }
+ break;
+#endif
case CI_DEFLATE:
+ case CI_DEFLATE_DRAFT:
if (optlen >= CILEN_DEFLATE) {
- printer(arg, "deflate %d", DEFLATE_SIZE(p[2]));
+ printer(arg, "deflate%s %d",
+ (code == CI_DEFLATE_DRAFT? "(old#)": ""),
+ DEFLATE_SIZE(p[2]));
if (DEFLATE_METHOD(p[2]) != DEFLATE_METHOD_VAL)
printer(arg, " method %d", DEFLATE_METHOD(p[2]));
if (p[3] != DEFLATE_CHK_SEQUENCE)
case TERMACK:
case TERMREQ:
if (len > 0 && *p >= ' ' && *p < 0x7f) {
- print_string(p, len, printer, arg);
+ print_string((char *)p, len, printer, arg);
p += len;
len = 0;
}
* compression :-(, otherwise we issue the reset-request.
*/
static void
-ccp_datainput(unit, pkt, len)
- int unit;
- u_char *pkt;
- int len;
+ccp_datainput(int unit, u_char *pkt, int len)
{
fsm *f;
/*
* Disable compression by taking CCP down.
*/
- syslog(LOG_ERR, "Lost compression sync: disabling compression");
+ error("Lost compression sync: disabling compression");
ccp_close(unit, "Lost compression sync");
+#ifdef PPP_WITH_MPPE
+ /*
+ * If we were doing MPPE, we must also take the link down.
+ */
+ if (ccp_gotoptions[unit].mppe) {
+ error("Too many MPPE errors, closing LCP");
+ lcp_close(unit, "Too many MPPE errors");
+ }
+#endif
} else {
/*
* Send a reset-request to reset the peer's compressor.
* Timeout waiting for reset-ack.
*/
static void
-ccp_rack_timeout(arg)
- void *arg;
+ccp_rack_timeout(void *arg)
{
fsm *f = arg;