summaryrefslogtreecommitdiff
path: root/libexec/pppd/lcp.c
diff options
context:
space:
mode:
Diffstat (limited to 'libexec/pppd/lcp.c')
-rw-r--r--libexec/pppd/lcp.c1191
1 files changed, 728 insertions, 463 deletions
diff --git a/libexec/pppd/lcp.c b/libexec/pppd/lcp.c
index d95a8faf575f..e991ef66d3a0 100644
--- a/libexec/pppd/lcp.c
+++ b/libexec/pppd/lcp.c
@@ -17,13 +17,13 @@
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
+#ifndef lint
+static char rcsid[] = "$Id: lcp.c,v 1.3 1994/03/30 09:38:14 jkh Exp $";
+#endif
+
/*
* TODO:
- * Keepalive.
- * Send NAKs for unsent CIs.
- * Keep separate MTU, MRU.
* Option tracing.
- * Extra data on authtype option.
* Test restart.
*/
@@ -35,19 +35,13 @@
#include <sys/time.h>
#include <net/if.h>
+#include <net/if_ppp.h>
#include <netinet/in.h>
#include <string.h>
-#ifdef STREAMS
-#include <sys/stream.h>
-#include "ppp_str.h"
-#endif
-
-#include <net/if_ppp.h>
#include "pppd.h"
-
-#include <net/ppp.h>
+#include "ppp.h"
#include "fsm.h"
#include "lcp.h"
#include "magic.h"
@@ -56,26 +50,28 @@
#include "ipcp.h"
/* global vars */
-fsm lcp_fsm[NPPP]; /* LCP fsm structure (global)*/
-lcp_options lcp_wantoptions[NPPP]; /* Options that we want to request */
-lcp_options lcp_gotoptions[NPPP]; /* Options that peer ack'd */
-lcp_options lcp_allowoptions[NPPP]; /* Options that we allow peer to request */
-lcp_options lcp_hisoptions[NPPP]; /* Options that we ack'd */
-
-/* local vars */
-static void lcp_resetci __ARGS((fsm *));
- /* Reset our Configuration Information */
-static int lcp_cilen __ARGS((fsm *)); /* Return length of our CI */
-static void lcp_addci __ARGS((fsm *, u_char *)); /* Add our CIs */
-static int lcp_ackci __ARGS((fsm *, u_char *, int)); /* Ack some CIs */
-static void lcp_nakci __ARGS((fsm *, u_char *, int)); /* Nak some CIs */
-static void lcp_rejci __ARGS((fsm *, u_char *, int));
- /* Reject some CIs */
-static u_char lcp_reqci __ARGS((fsm *, u_char *, int *));
- /* Check the requested CIs */
-static void lcp_up __ARGS((fsm *)); /* We're UP */
-static void lcp_down __ARGS((fsm *)); /* We're DOWN */
-static void lcp_closed __ARGS((fsm *)); /* We're CLOSED */
+fsm lcp_fsm[_NPPP]; /* LCP fsm structure (global)*/
+lcp_options lcp_wantoptions[_NPPP]; /* Options that we want to request */
+lcp_options lcp_gotoptions[_NPPP]; /* Options that peer ack'd */
+lcp_options lcp_allowoptions[_NPPP]; /* Options we allow peer to request */
+lcp_options lcp_hisoptions[_NPPP]; /* Options that we ack'd */
+
+/*
+ * Callbacks for fsm code. (CI = Configuration Information)
+ */
+static void lcp_resetci __ARGS((fsm *)); /* Reset our CI */
+static int lcp_cilen __ARGS((fsm *)); /* Return length of our CI */
+static void lcp_addci __ARGS((fsm *, u_char *, int *)); /* Add our CI to pkt */
+static int lcp_ackci __ARGS((fsm *, u_char *, int)); /* Peer ack'd our CI */
+static int lcp_nakci __ARGS((fsm *, u_char *, int)); /* Peer nak'd our CI */
+static int lcp_rejci __ARGS((fsm *, u_char *, int)); /* Peer rej'd our CI */
+static int lcp_reqci __ARGS((fsm *, u_char *, int *, int)); /* Rcv peer CI */
+static void lcp_up __ARGS((fsm *)); /* We're UP */
+static void lcp_down __ARGS((fsm *)); /* We're DOWN */
+static void lcp_starting __ARGS((fsm *)); /* We need lower layer up */
+static void lcp_finished __ARGS((fsm *)); /* We need lower layer down */
+static int lcp_extcode __ARGS((fsm *, int, int, u_char *, int));
+static void lcp_rprotrej __ARGS((fsm *, u_char *, int));
static fsm_callbacks lcp_callbacks = { /* LCP callback routines */
lcp_resetci, /* Reset our Configuration Information */
@@ -85,96 +81,104 @@ static fsm_callbacks lcp_callbacks = { /* LCP callback routines */
lcp_nakci, /* NAK our Configuration Information */
lcp_rejci, /* Reject our Configuration Information */
lcp_reqci, /* Request peer's Configuration Information */
- lcp_up, /* Called when fsm reaches OPEN state */
- lcp_down, /* Called when fsm leaves OPEN state */
- lcp_closed, /* Called when fsm reaches CLOSED state */
+ lcp_up, /* Called when fsm reaches OPENED state */
+ lcp_down, /* Called when fsm leaves OPENED state */
+ lcp_starting, /* Called when we want the lower layer up */
+ lcp_finished, /* Called when we want the lower layer down */
NULL, /* Called when Protocol-Reject received */
- NULL /* Retransmission is necessary */
+ NULL, /* Retransmission is necessary */
+ lcp_extcode, /* Called to handle LCP-specific codes */
+ "LCP" /* String name of protocol */
};
+int lcp_warnloops = DEFWARNLOOPS; /* Warn about a loopback this often */
+/*
+ * Length of each type of configuration option (in octets)
+ */
+#define CILEN_VOID 2
+#define CILEN_SHORT 4 /* CILEN_VOID + sizeof(short) */
+#define CILEN_CHAP 5 /* CILEN_VOID + sizeof(short) + 1 */
+#define CILEN_LONG 6 /* CILEN_VOID + sizeof(long) */
+#define CILEN_LQR 8 /* CILEN_VOID + sizeof(short) + sizeof(long) */
-
-#define DEFWARNLOOPS 10 /* XXX Move to lcp.h */
-static int lcp_warnloops = DEFWARNLOOPS; /* Warn about a loopback this often */
+#define CODENAME(x) ((x) == CONFACK ? "ACK" : \
+ (x) == CONFNAK ? "NAK" : "REJ")
/*
* lcp_init - Initialize LCP.
*/
void
- lcp_init(unit)
-int unit;
+lcp_init(unit)
+ int unit;
{
- fsm *f = &lcp_fsm[unit];
- lcp_options *wo = &lcp_wantoptions[unit];
- lcp_options *ao = &lcp_allowoptions[unit];
-
- f->unit = unit;
- f->protocol = LCP;
- f->timeouttime = DEFTIMEOUT;
- f->maxconfreqtransmits = DEFMAXCONFIGREQS;
- f->maxtermtransmits = DEFMAXTERMTRANSMITS;
- f->maxnakloops = DEFMAXNAKLOOPS;
- f->callbacks = &lcp_callbacks;
-
- wo->passive = 0;
- wo->restart = 0; /* Set to 1 in kernels or multi-line
- implementations */
+ fsm *f = &lcp_fsm[unit];
+ lcp_options *wo = &lcp_wantoptions[unit];
+ lcp_options *ao = &lcp_allowoptions[unit];
- wo->neg_mru = 1;
- wo->mru = DEFMRU;
- wo->neg_asyncmap = 1;
- wo->asyncmap = 0;
- wo->neg_chap = 0; /* Set to 1 on server */
- wo->neg_upap = 0; /* Set to 1 on server */
- wo->neg_magicnumber = 1;
- wo->neg_pcompression = 1;
- wo->neg_accompression = 1;
-
- ao->neg_mru = 1;
- ao->neg_asyncmap = 1;
- ao->neg_chap = 0; /* Set to 1 on client */
- ao->chap_mdtype = CHAP_DIGEST_MD5;
- ao->chap_callback = CHAP_NOCALLBACK;
- ao->neg_upap = 0; /* Set to 1 on client */
-
- ao->neg_magicnumber = 1;
- ao->neg_pcompression = 1;
- ao->neg_accompression = 1;
-
- fsm_init(f);
-}
+ f->unit = unit;
+ f->protocol = LCP;
+ f->callbacks = &lcp_callbacks;
+ fsm_init(f);
+
+ wo->passive = 0;
+ wo->silent = 0;
+ wo->restart = 0; /* Set to 1 in kernels or multi-line
+ implementations */
+ wo->neg_mru = 1;
+ wo->mru = DEFMRU;
+ wo->neg_asyncmap = 1;
+ wo->asyncmap = 0;
+ wo->neg_chap = 0; /* Set to 1 on server */
+ wo->neg_upap = 0; /* Set to 1 on server */
+ wo->chap_mdtype = CHAP_DIGEST_MD5;
+ wo->neg_magicnumber = 1;
+ wo->neg_pcompression = 1;
+ wo->neg_accompression = 1;
+ wo->neg_lqr = 0; /* no LQR implementation yet */
+
+ ao->neg_mru = 1;
+ ao->mru = MAXMRU;
+ ao->neg_asyncmap = 1;
+ ao->asyncmap = 0;
+ ao->neg_chap = 1;
+ ao->chap_mdtype = CHAP_DIGEST_MD5;
+ ao->neg_upap = 1;
+ ao->neg_magicnumber = 1;
+ ao->neg_pcompression = 1;
+ ao->neg_accompression = 1;
+ ao->neg_lqr = 0; /* no LQR implementation yet */
-/*
- * lcp_activeopen - Actively open LCP.
- */
-void
- lcp_activeopen(unit)
-int unit;
-{
- fsm_activeopen(&lcp_fsm[unit]);
}
/*
- * lcp_passiveopen - Passively open LCP.
+ * lcp_open - LCP is allowed to come up.
*/
void
- lcp_passiveopen(unit)
-int unit;
+lcp_open(unit)
+ int unit;
{
- fsm_passiveopen(&lcp_fsm[unit]);
+ fsm *f = &lcp_fsm[unit];
+ lcp_options *wo = &lcp_wantoptions[unit];
+
+ f->flags = 0;
+ if (wo->passive)
+ f->flags |= OPT_PASSIVE;
+ if (wo->silent)
+ f->flags |= OPT_SILENT;
+ fsm_open(f);
}
/*
- * lcp_close - Close LCP.
+ * lcp_close - Take LCP down.
*/
void
- lcp_close(unit)
-int unit;
+lcp_close(unit)
+ int unit;
{
fsm_close(&lcp_fsm[unit]);
}
@@ -184,14 +188,13 @@ int unit;
* lcp_lowerup - The lower layer is up.
*/
void
- lcp_lowerup(unit)
-int unit;
+lcp_lowerup(unit)
+ int unit;
{
- SIFDOWN(unit);
- SIFMTU(unit, MTU);
- SIFASYNCMAP(unit, 0xffffffff);
- CIFPCOMPRESSION(unit);
- CIFACCOMPRESSION(unit);
+ sifdown(unit);
+ ppp_send_config(unit, MTU, 0xffffffff, 0, 0);
+ ppp_recv_config(unit, MTU, 0, 0, 0);
+ peer_mru[unit] = MTU;
fsm_lowerup(&lcp_fsm[unit]);
}
@@ -201,8 +204,8 @@ int unit;
* lcp_lowerdown - The lower layer is down.
*/
void
- lcp_lowerdown(unit)
-int unit;
+lcp_lowerdown(unit)
+ int unit;
{
fsm_lowerdown(&lcp_fsm[unit]);
}
@@ -212,28 +215,103 @@ int unit;
* lcp_input - Input LCP packet.
*/
void
- lcp_input(unit, p, len)
-int unit;
-u_char *p;
-int len;
+lcp_input(unit, p, len)
+ int unit;
+ u_char *p;
+ int len;
{
fsm_input(&lcp_fsm[unit], p, len);
}
/*
+ * lcp_extcode - Handle a LCP-specific code.
+ */
+static int
+lcp_extcode(f, code, id, inp, len)
+ fsm *f;
+ int code, id;
+ u_char *inp;
+ int len;
+{
+ switch( code ){
+ case PROTREJ:
+ lcp_rprotrej(f, inp, len);
+ break;
+
+ case ECHOREQ:
+ if( f->state != OPENED )
+ break;
+ LCPDEBUG((LOG_INFO, "lcp: Echo-Request, Rcvd id %d", id));
+ fsm_sdata(f, ECHOREP, id, inp, len);
+ break;
+
+ case ECHOREP:
+ case DISCREQ:
+ break;
+
+ default:
+ return 0;
+ }
+ return 1;
+}
+
+
+/*
+ * lcp_rprotrej - Receive an Protocol-Reject.
+ *
+ * Figure out which protocol is rejected and inform it.
+ */
+static void
+lcp_rprotrej(f, inp, len)
+ fsm *f;
+ u_char *inp;
+ int len;
+{
+ u_short prot;
+
+ LCPDEBUG((LOG_INFO, "lcp_rprotrej."));
+
+ if (len < sizeof (u_short)) {
+ LCPDEBUG((LOG_INFO,
+ "lcp_rprotrej: Rcvd short Protocol-Reject packet!"));
+ return;
+ }
+
+ GETSHORT(prot, inp);
+
+ LCPDEBUG((LOG_INFO,
+ "lcp_rprotrej: Rcvd Protocol-Reject packet for %x!",
+ prot));
+
+ /*
+ * Protocol-Reject packets received in any state other than the LCP
+ * OPENED state SHOULD be silently discarded.
+ */
+ if( f->state != OPENED ){
+ LCPDEBUG((LOG_INFO, "Protocol-Reject discarded: LCP in state %d",
+ f->state));
+ return;
+ }
+
+ DEMUXPROTREJ(f->unit, prot); /* Inform protocol */
+}
+
+
+/*
* lcp_protrej - A Protocol-Reject was received.
*/
/*ARGSUSED*/
void
- lcp_protrej(unit)
-int unit;
+lcp_protrej(unit)
+ int unit;
{
/*
* Can't reject LCP!
*/
LCPDEBUG((LOG_WARNING,
- "lcp_protrej: Received Protocol-Reject for LCP!"))
+ "lcp_protrej: Received Protocol-Reject for LCP!"));
+ fsm_protreject(&lcp_fsm[unit]);
}
@@ -241,13 +319,14 @@ int unit;
* lcp_sprotrej - Send a Protocol-Reject for some protocol.
*/
void
- lcp_sprotrej(unit, p, len)
-int unit;
-u_char *p;
-int len;
+lcp_sprotrej(unit, p, len)
+ int unit;
+ u_char *p;
+ int len;
{
- /* this is marginal, as rejected-info should be full frame,
- * but at least we return the rejected-protocol
+ /*
+ * Send back the protocol and the information field of the
+ * rejected packet. We only get here if LCP is in the OPENED state.
*/
p += 2;
len -= 2;
@@ -267,6 +346,7 @@ fsm *f;
lcp_wantoptions[f->unit].magicnumber = magic();
lcp_wantoptions[f->unit].numloops = 0;
lcp_gotoptions[f->unit] = lcp_wantoptions[f->unit];
+ peer_mru[f->unit] = MTU;
}
@@ -274,20 +354,25 @@ fsm *f;
* lcp_cilen - Return length of our CI.
*/
static int
- lcp_cilen(f)
-fsm *f;
+lcp_cilen(f)
+ fsm *f;
{
lcp_options *go = &lcp_gotoptions[f->unit];
-#define LENCIVOID(neg) (neg ? 2 : 0)
-#define LENCICHAP(neg) (neg ? 6 : 0)
-#define LENCISHORT(neg) (neg ? 4 : 0)
-#define LENCILONG(neg) (neg ? 6 : 0)
-
+#define LENCIVOID(neg) (neg ? CILEN_VOID : 0)
+#define LENCICHAP(neg) (neg ? CILEN_CHAP : 0)
+#define LENCISHORT(neg) (neg ? CILEN_SHORT : 0)
+#define LENCILONG(neg) (neg ? CILEN_LONG : 0)
+#define LENCILQR(neg) (neg ? CILEN_LQR: 0)
+ /*
+ * NB: we only ask for one of CHAP and UPAP, even if we will
+ * accept either.
+ */
return (LENCISHORT(go->neg_mru) +
LENCILONG(go->neg_asyncmap) +
LENCICHAP(go->neg_chap) +
- LENCISHORT(go->neg_upap) +
+ LENCISHORT(!go->neg_chap && go->neg_upap) +
+ LENCILQR(go->neg_lqr) +
LENCILONG(go->neg_magicnumber) +
LENCIVOID(go->neg_pcompression) +
LENCIVOID(go->neg_accompression));
@@ -298,60 +383,75 @@ fsm *f;
* lcp_addci - Add our desired CIs to a packet.
*/
static void
- lcp_addci(f, ucp)
-fsm *f;
-u_char *ucp;
+lcp_addci(f, ucp, lenp)
+ fsm *f;
+ u_char *ucp;
+ int *lenp;
{
lcp_options *go = &lcp_gotoptions[f->unit];
+ u_char *start_ucp = ucp;
#define ADDCIVOID(opt, neg) \
if (neg) { \
PUTCHAR(opt, ucp); \
- PUTCHAR(2, ucp); \
+ PUTCHAR(CILEN_VOID, ucp); \
}
#define ADDCISHORT(opt, neg, val) \
if (neg) { \
PUTCHAR(opt, ucp); \
- PUTCHAR(2 + sizeof (short), ucp); \
+ PUTCHAR(CILEN_SHORT, ucp); \
PUTSHORT(val, ucp); \
}
-#define ADDCICHAP(opt, neg, val, digest, callback) \
+#define ADDCICHAP(opt, neg, val, digest) \
if (neg) { \
PUTCHAR(opt, ucp); \
- PUTCHAR(6, ucp); \
+ PUTCHAR(CILEN_CHAP, ucp); \
PUTSHORT(val, ucp); \
PUTCHAR(digest, ucp); \
- PUTCHAR(callback, ucp); \
}
#define ADDCILONG(opt, neg, val) \
if (neg) { \
PUTCHAR(opt, ucp); \
- PUTCHAR(2 + sizeof (long), ucp); \
+ PUTCHAR(CILEN_LONG, ucp); \
+ PUTLONG(val, ucp); \
+ }
+#define ADDCILQR(opt, neg, val) \
+ if (neg) { \
+ PUTCHAR(opt, ucp); \
+ PUTCHAR(CILEN_LQR, ucp); \
+ PUTSHORT(LQR, ucp); \
PUTLONG(val, ucp); \
}
- ADDCISHORT(CI_MRU, go->neg_mru, go->mru)
- ADDCILONG(CI_ASYNCMAP, go->neg_asyncmap, go->asyncmap)
- ADDCICHAP(CI_AUTHTYPE, go->neg_chap, CHAP, go->chap_mdtype, go->chap_callback)
- ADDCISHORT(CI_AUTHTYPE, go->neg_upap, UPAP)
- ADDCILONG(CI_MAGICNUMBER, go->neg_magicnumber, go->magicnumber)
- ADDCIVOID(CI_PCOMPRESSION, go->neg_pcompression)
- ADDCIVOID(CI_ACCOMPRESSION, go->neg_accompression)
+ ADDCISHORT(CI_MRU, go->neg_mru, go->mru);
+ ADDCILONG(CI_ASYNCMAP, go->neg_asyncmap, go->asyncmap);
+ ADDCICHAP(CI_AUTHTYPE, go->neg_chap, CHAP, go->chap_mdtype);
+ ADDCISHORT(CI_AUTHTYPE, !go->neg_chap && go->neg_upap, UPAP);
+ ADDCILQR(CI_QUALITY, go->neg_lqr, go->lqr_period);
+ ADDCILONG(CI_MAGICNUMBER, go->neg_magicnumber, go->magicnumber);
+ ADDCIVOID(CI_PCOMPRESSION, go->neg_pcompression);
+ ADDCIVOID(CI_ACCOMPRESSION, go->neg_accompression);
+
+ if (ucp - start_ucp != *lenp) {
+ /* this should never happen, because peer_mtu should be 1500 */
+ syslog(LOG_ERR, "Bug in lcp_addci: wrong length");
+ }
}
/*
* lcp_ackci - Ack our CIs.
+ * This should not modify any state if the Ack is bad.
*
* Returns:
* 0 - Ack was bad.
* 1 - Ack was good.
*/
static int
- lcp_ackci(f, p, len)
-fsm *f;
-u_char *p;
-int len;
+lcp_ackci(f, p, len)
+ fsm *f;
+ u_char *p;
+ int len;
{
lcp_options *go = &lcp_gotoptions[f->unit];
u_char cilen, citype, cichar;
@@ -365,34 +465,34 @@ int len;
*/
#define ACKCIVOID(opt, neg) \
if (neg) { \
- if ((len -= 2) < 0) \
+ if ((len -= CILEN_VOID) < 0) \
goto bad; \
GETCHAR(citype, p); \
GETCHAR(cilen, p); \
- if (cilen != 2 || \
+ if (cilen != CILEN_VOID || \
citype != opt) \
goto bad; \
}
#define ACKCISHORT(opt, neg, val) \
if (neg) { \
- if ((len -= 2 + sizeof (short)) < 0) \
+ if ((len -= CILEN_SHORT) < 0) \
goto bad; \
GETCHAR(citype, p); \
GETCHAR(cilen, p); \
- if (cilen != 2 + sizeof (short) || \
+ if (cilen != CILEN_SHORT || \
citype != opt) \
goto bad; \
GETSHORT(cishort, p); \
if (cishort != val) \
goto bad; \
}
-#define ACKCICHAP(opt, neg, val, digest, callback) \
+#define ACKCICHAP(opt, neg, val, digest) \
if (neg) { \
- if ((len -= 4 + sizeof (short)) < 0) \
+ if ((len -= CILEN_CHAP) < 0) \
goto bad; \
GETCHAR(citype, p); \
GETCHAR(cilen, p); \
- if (cilen != 4 + sizeof (short) || \
+ if (cilen != CILEN_CHAP || \
citype != opt) \
goto bad; \
GETSHORT(cishort, p); \
@@ -401,31 +501,45 @@ int len;
GETCHAR(cichar, p); \
if (cichar != digest) \
goto bad; \
- GETCHAR(cichar, p); \
- if (cichar != callback) \
- goto bad; \
}
#define ACKCILONG(opt, neg, val) \
if (neg) { \
- if ((len -= 2 + sizeof (long)) < 0) \
+ if ((len -= CILEN_LONG) < 0) \
goto bad; \
GETCHAR(citype, p); \
GETCHAR(cilen, p); \
- if (cilen != 2 + sizeof (long) || \
+ if (cilen != CILEN_LONG || \
citype != opt) \
goto bad; \
GETLONG(cilong, p); \
if (cilong != val) \
goto bad; \
}
+#define ACKCILQR(opt, neg, val) \
+ if (neg) { \
+ if ((len -= CILEN_LQR) < 0) \
+ goto bad; \
+ GETCHAR(citype, p); \
+ GETCHAR(cilen, p); \
+ if (cilen != CILEN_LQR || \
+ citype != opt) \
+ goto bad; \
+ GETSHORT(cishort, p); \
+ if (cishort != LQR) \
+ goto bad; \
+ GETLONG(cilong, p); \
+ if (cilong != val) \
+ goto bad; \
+ }
- ACKCISHORT(CI_MRU, go->neg_mru, go->mru)
- ACKCILONG(CI_ASYNCMAP, go->neg_asyncmap, go->asyncmap)
- ACKCICHAP(CI_AUTHTYPE, go->neg_chap, CHAP, go->chap_mdtype, go->chap_callback)
- ACKCISHORT(CI_AUTHTYPE, go->neg_upap, UPAP)
- ACKCILONG(CI_MAGICNUMBER, go->neg_magicnumber, go->magicnumber)
- ACKCIVOID(CI_PCOMPRESSION, go->neg_pcompression)
- ACKCIVOID(CI_ACCOMPRESSION, go->neg_accompression)
+ ACKCISHORT(CI_MRU, go->neg_mru, go->mru);
+ ACKCILONG(CI_ASYNCMAP, go->neg_asyncmap, go->asyncmap);
+ ACKCICHAP(CI_AUTHTYPE, go->neg_chap, CHAP, go->chap_mdtype);
+ ACKCISHORT(CI_AUTHTYPE, !go->neg_chap && go->neg_upap, UPAP);
+ ACKCILQR(CI_QUALITY, go->neg_lqr, go->lqr_period);
+ ACKCILONG(CI_MAGICNUMBER, go->neg_magicnumber, go->magicnumber);
+ ACKCIVOID(CI_PCOMPRESSION, go->neg_pcompression);
+ ACKCIVOID(CI_ACCOMPRESSION, go->neg_accompression);
/*
* If there are any remaining CIs, then this packet is bad.
@@ -434,67 +548,97 @@ int len;
goto bad;
return (1);
bad:
- LCPDEBUG((LOG_WARNING, "lcp_acki: received bad Ack!"))
+ LCPDEBUG((LOG_WARNING, "lcp_acki: received bad Ack!"));
return (0);
}
/*
- * lcp_nakci - NAK some of our CIs.
+ * lcp_nakci - Peer has sent a NAK for some of our CIs.
+ * This should not modify any state if the Nak is bad
+ * or if LCP is in the OPENED state.
+ *
+ * Returns:
+ * 0 - Nak was bad.
+ * 1 - Nak was good.
*/
-static void
- lcp_nakci(f, p, len)
-fsm *f;
-u_char *p;
-int len;
+static int
+lcp_nakci(f, p, len)
+ fsm *f;
+ u_char *p;
+ int len;
{
lcp_options *go = &lcp_gotoptions[f->unit];
lcp_options *wo = &lcp_wantoptions[f->unit];
+ u_char cilen, citype, cichar, *next;
u_short cishort;
u_long cilong;
+ lcp_options no; /* options we've seen Naks for */
+ lcp_options try; /* options to request next time */
+ int looped_back = 0;
+
+ BZERO(&no, sizeof(no));
+ try = *go;
+
/*
* Any Nak'd CIs must be in exactly the same order that we sent.
* Check packet length and CI length at each step.
* If we find any deviations, then this packet is bad.
*/
#define NAKCIVOID(opt, neg, code) \
- if (neg && \
- len >= 2 && \
- p[1] == 2 && \
+ if (go->neg && \
+ len >= CILEN_VOID && \
+ p[1] == CILEN_VOID && \
p[0] == opt) { \
- len -= 2; \
- INCPTR(2, p); \
+ len -= CILEN_VOID; \
+ INCPTR(CILEN_VOID, p); \
+ no.neg = 1; \
code \
}
-#define NAKCICHAP(opt, neg, digest, callback, code) \
- if (neg && \
- len >= 4 + sizeof (short) && \
- p[1] == 4 + sizeof (short) && \
+#define NAKCICHAP(opt, neg, code) \
+ if (go->neg && \
+ len >= CILEN_CHAP && \
+ p[1] == CILEN_CHAP && \
p[0] == opt) { \
- len -= 4 + sizeof (short); \
+ len -= CILEN_CHAP; \
INCPTR(2, p); \
GETSHORT(cishort, p); \
- INCPTR(2, p); \
+ GETCHAR(cichar, p); \
+ no.neg = 1; \
code \
}
#define NAKCISHORT(opt, neg, code) \
- if (neg && \
- len >= 2 + sizeof (short) && \
- p[1] == 2 + sizeof (short) && \
+ if (go->neg && \
+ len >= CILEN_SHORT && \
+ p[1] == CILEN_SHORT && \
p[0] == opt) { \
- len -= 2 + sizeof (short); \
+ len -= CILEN_SHORT; \
INCPTR(2, p); \
GETSHORT(cishort, p); \
+ no.neg = 1; \
code \
}
#define NAKCILONG(opt, neg, code) \
- if (neg && \
- len >= 2 + sizeof (long) && \
- p[1] == 2 + sizeof (long) && \
+ if (go->neg && \
+ len >= CILEN_LONG && \
+ p[1] == CILEN_LONG && \
p[0] == opt) { \
- len -= 2 + sizeof (long); \
+ len -= CILEN_LONG; \
INCPTR(2, p); \
GETLONG(cilong, p); \
+ no.neg = 1; \
+ code \
+ }
+#define NAKCILQR(opt, neg, code) \
+ if (go->neg && \
+ len >= CILEN_LQR && \
+ p[1] == CILEN_LQR && \
+ p[0] == opt) { \
+ len -= CILEN_LQR; \
+ INCPTR(2, p); \
+ GETSHORT(cishort, p); \
+ GETLONG(cilong, p); \
+ no.neg = 1; \
code \
}
@@ -502,143 +646,270 @@ int len;
* We don't care if they want to send us smaller packets than
* we want. Therefore, accept any MRU less than what we asked for,
* but then ignore the new value when setting the MRU in the kernel.
- * If they send us a bigger MRU than what we asked, reject it and
- * let him decide to accept our value.
+ * If they send us a bigger MRU than what we asked, accept it, up to
+ * the limit of the default MRU we'd get if we didn't negotiate.
+ */
+ NAKCISHORT(CI_MRU, neg_mru,
+ if (cishort <= wo->mru || cishort < DEFMRU)
+ try.mru = cishort;
+ );
+ /*
+ * Add any characters they want to our (receive-side) asyncmap.
+ */
+ NAKCILONG(CI_ASYNCMAP, neg_asyncmap,
+ try.asyncmap = go->asyncmap | cilong;
+ );
+ /*
+ * If they can't cope with our CHAP hash algorithm, we'll have
+ * to stop asking for CHAP. We haven't got any other algorithm.
+ */
+ NAKCICHAP(CI_AUTHTYPE, neg_chap,
+ try.neg_chap = 0;
+ );
+ /*
+ * Peer shouldn't send Nak for UPAP, protocol compression or
+ * address/control compression requests; they should send
+ * a Reject instead. If they send a Nak, treat it as a Reject.
+ */
+ if (!go->neg_chap ){
+ NAKCISHORT(CI_AUTHTYPE, neg_upap,
+ try.neg_upap = 0;
+ );
+ }
+ /*
+ * If they can't cope with our link quality protocol, we'll have
+ * to stop asking for LQR. We haven't got any other protocol.
+ * If they Nak the reporting period, take their value XXX ?
+ */
+ NAKCILONG(CI_QUALITY, neg_lqr,
+ if (cishort != LQR)
+ try.neg_lqr = 0;
+ else
+ try.lqr_period = cilong;
+ );
+ /*
+ * Check for a looped-back line.
*/
- NAKCISHORT(CI_MRU, go->neg_mru,
- if (cishort <= wo->mru)
- go->mru = cishort;
- else
- goto bad;
- )
- NAKCILONG(CI_ASYNCMAP, go->neg_asyncmap,
- go->asyncmap |= cilong;
- )
- NAKCICHAP(CI_AUTHTYPE, go->neg_chap, go->chap_mdtype, go->chap_callback,
- LCPDEBUG((LOG_WARNING, "Peer refuses to authenticate chap!"))
- )
- NAKCISHORT(CI_AUTHTYPE, go->neg_upap,
- LCPDEBUG((LOG_WARNING, "Peer refuses to authenticate pap!"))
- )
- NAKCILONG(CI_MAGICNUMBER, go->neg_magicnumber,
- go->magicnumber = magic();
- if (++go->numloops % lcp_warnloops == 0)
- LCPDEBUG((LOG_INFO, "The line appears to be looped back."))
- )
- NAKCIVOID(CI_PCOMPRESSION, go->neg_pcompression,
- go->neg_pcompression = 0;
- )
- NAKCIVOID(CI_ACCOMPRESSION, go->neg_accompression,
- go->neg_accompression = 0;
- )
+ NAKCILONG(CI_MAGICNUMBER, neg_magicnumber,
+ try.magicnumber = magic();
+ ++try.numloops;
+ looped_back = 1;
+ );
+
+ NAKCIVOID(CI_PCOMPRESSION, neg_pcompression,
+ try.neg_pcompression = 0;
+ );
+ NAKCIVOID(CI_ACCOMPRESSION, neg_accompression,
+ try.neg_accompression = 0;
+ );
/*
- * If there are any remaining CIs, then this packet is bad.
+ * There may be remaining CIs, if the peer is requesting negotiation
+ * on an option that we didn't include in our request packet.
+ * If we see an option that we requested, or one we've already seen
+ * in this packet, then this packet is bad.
+ * If we wanted to respond by starting to negotiate on the requested
+ * option(s), we could, but we don't, because except for the
+ * authentication type and quality protocol, if we are not negotiating
+ * an option, it is because we were told not to.
+ * For the authentication type, the Nak from the peer means
+ * `let me authenticate myself with you' which is a bit pointless.
+ * For the quality protocol, the Nak means `ask me to send you quality
+ * reports', but if we didn't ask for them, we don't want them.
*/
- if (len == 0)
- return;
+ while (len > CILEN_VOID) {
+ GETCHAR(citype, p);
+ GETCHAR(cilen, p);
+ if( (len -= cilen) < 0 )
+ goto bad;
+ next = p + cilen - 2;
+
+ switch (citype) {
+ case CI_MRU:
+ if (go->neg_mru || no.neg_mru || cilen != CILEN_SHORT)
+ goto bad;
+ break;
+ case CI_ASYNCMAP:
+ if (go->neg_asyncmap || no.neg_asyncmap || cilen != CILEN_LONG)
+ goto bad;
+ break;
+ case CI_AUTHTYPE:
+ if (go->neg_chap || no.neg_chap || go->neg_upap || no.neg_upap)
+ goto bad;
+ break;
+ case CI_MAGICNUMBER:
+ if (go->neg_magicnumber || no.neg_magicnumber ||
+ cilen != CILEN_LONG)
+ goto bad;
+ break;
+ case CI_PCOMPRESSION:
+ if (go->neg_pcompression || no.neg_pcompression
+ || cilen != CILEN_VOID)
+ goto bad;
+ break;
+ case CI_ACCOMPRESSION:
+ if (go->neg_accompression || no.neg_accompression
+ || cilen != CILEN_VOID)
+ goto bad;
+ break;
+ case CI_QUALITY:
+ if (go->neg_lqr || no.neg_lqr || cilen != CILEN_LQR)
+ goto bad;
+ break;
+ default:
+ goto bad;
+ }
+ p = next;
+ }
+
+ /* If there is still anything left, this packet is bad. */
+ if (len != 0)
+ goto bad;
+
+ /*
+ * OK, the Nak is good. Now we can update state.
+ */
+ if (f->state != OPENED) {
+ *go = try;
+ if (looped_back && try.numloops % lcp_warnloops == 0)
+ LCPDEBUG((LOG_INFO, "The line appears to be looped back."));
+ }
+
+ return 1;
+
bad:
- LCPDEBUG((LOG_WARNING, "lcp_nakci: received bad Nak!"))
+ LCPDEBUG((LOG_WARNING, "lcp_nakci: received bad Nak!"));
+ return 0;
}
/*
- * lcp_rejci - Reject some of our CIs.
+ * lcp_rejci - Peer has Rejected some of our CIs.
+ * This should not modify any state if the Reject is bad
+ * or if LCP is in the OPENED state.
+ *
+ * Returns:
+ * 0 - Reject was bad.
+ * 1 - Reject was good.
*/
-static void
- lcp_rejci(f, p, len)
-fsm *f;
-u_char *p;
-int len;
+static int
+lcp_rejci(f, p, len)
+ fsm *f;
+ u_char *p;
+ int len;
{
lcp_options *go = &lcp_gotoptions[f->unit];
+ u_char cichar;
u_short cishort;
u_long cilong;
u_char *start = p;
- int myopt, myval, xval, plen = len;
+ int plen = len;
+ lcp_options try; /* options to request next time */
+
+ try = *go;
+
/*
* Any Rejected CIs must be in exactly the same order that we sent.
* Check packet length and CI length at each step.
* If we find any deviations, then this packet is bad.
*/
#define REJCIVOID(opt, neg) \
- myopt = opt; \
- if (neg && \
- len >= 2 && \
- p[1] == 2 && \
+ if (go->neg && \
+ len >= CILEN_VOID && \
+ p[1] == CILEN_VOID && \
p[0] == opt) { \
- len -= 2; \
- INCPTR(2, p); \
- neg = 0; \
- LCPDEBUG((LOG_INFO,"lcp_rejci rejected void opt %d",opt)) \
+ len -= CILEN_VOID; \
+ INCPTR(CILEN_VOID, p); \
+ try.neg = 0; \
+ LCPDEBUG((LOG_INFO, "lcp_rejci rejected void opt %d", opt)); \
}
#define REJCISHORT(opt, neg, val) \
- myopt = opt; myval = val; \
- if (neg && \
- len >= 2 + sizeof (short) && \
- p[1] == 2 + sizeof (short) && \
+ if (go->neg && \
+ len >= CILEN_SHORT && \
+ p[1] == CILEN_SHORT && \
p[0] == opt) { \
- len -= 2 + sizeof (short); \
+ len -= CILEN_SHORT; \
INCPTR(2, p); \
GETSHORT(cishort, p); \
/* Check rejected value. */ \
- xval = cishort; \
if (cishort != val) \
goto bad; \
- neg = 0; \
- LCPDEBUG((LOG_INFO,"lcp_rejci rejected short opt %d", opt)) \
+ try.neg = 0; \
+ LCPDEBUG((LOG_INFO,"lcp_rejci rejected short opt %d", opt)); \
}
-#define REJCICHAP(opt, neg, val, digest, callback) \
- myopt = opt; myval = val; \
- if (neg && \
- len >= 4 + sizeof (short) && \
- p[1] == 4 + sizeof (short) && \
+#define REJCICHAP(opt, neg, val, digest) \
+ if (go->neg && \
+ len >= CILEN_CHAP && \
+ p[1] == CILEN_CHAP && \
p[0] == opt) { \
- len -= 4 + sizeof (short); \
+ len -= CILEN_CHAP; \
INCPTR(2, p); \
GETSHORT(cishort, p); \
+ GETCHAR(cichar, p); \
/* Check rejected value. */ \
- xval = cishort; \
- if (cishort != val) \
+ if (cishort != val || cichar != digest) \
goto bad; \
- neg = 0; \
- INCPTR(2, p); \
- LCPDEBUG((LOG_INFO,"lcp_rejci rejected chap opt %d", opt)) \
+ try.neg = 0; \
+ LCPDEBUG((LOG_INFO,"lcp_rejci rejected chap opt %d", opt)); \
}
#define REJCILONG(opt, neg, val) \
- myopt = opt; myval = val; \
- if (neg && \
- len >= 2 + sizeof (long) && \
- p[1] == 2 + sizeof (long) && \
+ if (go->neg && \
+ len >= CILEN_LONG && \
+ p[1] == CILEN_LONG && \
p[0] == opt) { \
- len -= 2 + sizeof (long); \
+ len -= CILEN_LONG; \
INCPTR(2, p); \
GETLONG(cilong, p); \
- xval = cilong; \
/* Check rejected value. */ \
if (cilong != val) \
goto bad; \
- neg = 0; \
- LCPDEBUG((LOG_INFO,"lcp_rejci rejected long opt %d", opt)) \
+ try.neg = 0; \
+ LCPDEBUG((LOG_INFO,"lcp_rejci rejected long opt %d", opt)); \
+ }
+#define REJCILQR(opt, neg, val) \
+ if (go->neg && \
+ len >= CILEN_LQR && \
+ p[1] == CILEN_LQR && \
+ p[0] == opt) { \
+ len -= CILEN_LQR; \
+ INCPTR(2, p); \
+ GETSHORT(cishort, p); \
+ GETLONG(cilong, p); \
+ /* Check rejected value. */ \
+ if (cishort != LQR || cichar != val) \
+ goto bad; \
+ try.neg = 0; \
+ LCPDEBUG((LOG_INFO,"lcp_rejci rejected LQR opt %d", opt)); \
}
- REJCISHORT(CI_MRU, go->neg_mru, go->mru)
- REJCILONG(CI_ASYNCMAP, go->neg_asyncmap, go->asyncmap)
- REJCICHAP(CI_AUTHTYPE, go->neg_chap, CHAP, go->chap_mdtype, go->callback)
- REJCISHORT(CI_AUTHTYPE, go->neg_upap, UPAP)
- REJCILONG(CI_MAGICNUMBER, go->neg_magicnumber, go->magicnumber)
- REJCIVOID(CI_PCOMPRESSION, go->neg_pcompression)
- REJCIVOID(CI_ACCOMPRESSION, go->neg_accompression)
+ REJCISHORT(CI_MRU, neg_mru, go->mru);
+ REJCILONG(CI_ASYNCMAP, neg_asyncmap, go->asyncmap);
+ REJCICHAP(CI_AUTHTYPE, neg_chap, CHAP, go->chap_mdtype);
+ if (!go->neg_chap) {
+ REJCISHORT(CI_AUTHTYPE, neg_upap, UPAP);
+ }
+ REJCILQR(CI_QUALITY, neg_lqr, go->lqr_period);
+ REJCILONG(CI_MAGICNUMBER, neg_magicnumber, go->magicnumber);
+ REJCIVOID(CI_PCOMPRESSION, neg_pcompression);
+ REJCIVOID(CI_ACCOMPRESSION, neg_accompression);
/*
* If there are any remaining CIs, then this packet is bad.
*/
- if (len == 0)
- return;
+ if (len != 0)
+ goto bad;
+ /*
+ * Now we can update state.
+ */
+ if (f->state != OPENED)
+ *go = try;
+ return 1;
+
bad:
- LCPDEBUG((LOG_WARNING, "lcp_rejci: received bad Reject!"))
- LCPDEBUG((LOG_WARNING, "lcp_rejci: plen %d len %d off %d, exp opt %d, found %d, val %d fval %d ",
- plen, len, p - start, myopt, p[0] &0xff, myval, xval ))
+ LCPDEBUG((LOG_WARNING, "lcp_rejci: received bad Reject!"));
+ LCPDEBUG((LOG_WARNING, "lcp_rejci: plen %d len %d off %d",
+ plen, len, p - start));
+ return 0;
}
@@ -646,48 +917,45 @@ bad:
* lcp_reqci - Check the peer's requested CIs and send appropriate response.
*
* Returns: CONFACK, CONFNAK or CONFREJ and input packet modified
- * appropriately.
+ * appropriately. If reject_if_disagree is non-zero, doesn't return
+ * CONFNAK; returns CONFREJ if it can't return CONFACK.
*/
-static u_char
- lcp_reqci(f, inp, len)
-fsm *f;
-u_char *inp; /* Requested CIs */
-int *len; /* Length of requested CIs */
+static int
+lcp_reqci(f, inp, lenp, reject_if_disagree)
+ fsm *f;
+ u_char *inp; /* Requested CIs */
+ int *lenp; /* Length of requested CIs */
+ int reject_if_disagree;
{
lcp_options *go = &lcp_gotoptions[f->unit];
lcp_options *ho = &lcp_hisoptions[f->unit];
lcp_options *ao = &lcp_allowoptions[f->unit];
- u_char *cip; /* Pointer to Current CI */
+ u_char *cip, *next; /* Pointer to current and next CIs */
u_char cilen, citype, cichar;/* Parsed len, type, char value */
u_short cishort; /* Parsed short value */
u_long cilong; /* Parse long value */
int rc = CONFACK; /* Final packet return code */
int orc; /* Individual option return code */
- u_char *p = inp; /* Pointer to next char to parse */
+ u_char *p; /* Pointer to next char to parse */
u_char *ucp = inp; /* Pointer to current output char */
- int l = *len; /* Length left */
+ int l = *lenp; /* Length left */
/*
* Reset all his options.
*/
- ho->neg_mru = 0;
- ho->neg_asyncmap = 0;
- ho->neg_chap = 0;
- ho->neg_upap = 0;
- ho->neg_magicnumber = 0;
- ho->neg_pcompression = 0;
- ho->neg_accompression = 0;
+ BZERO(ho, sizeof(*ho));
/*
* Process all his options.
*/
+ next = inp;
while (l) {
orc = CONFACK; /* Assume success */
- cip = p; /* Remember begining of CI */
+ cip = p = next; /* Remember begining of CI */
if (l < 2 || /* Not enough data for CI header or */
p[1] < 2 || /* CI length too small or */
p[1] > l) { /* CI length too big? */
- LCPDEBUG((LOG_WARNING, "lcp_reqci: bad CI length!"))
+ LCPDEBUG((LOG_WARNING, "lcp_reqci: bad CI length!"));
orc = CONFREJ; /* Reject bad CI */
cilen = l; /* Reject till end of packet */
l = 0; /* Don't loop again */
@@ -696,19 +964,18 @@ int *len; /* Length of requested CIs */
GETCHAR(citype, p); /* Parse CI type */
GETCHAR(cilen, p); /* Parse CI length */
l -= cilen; /* Adjust remaining length */
- cilen -= 2; /* Adjust cilen to just data */
+ next += cilen; /* Step to next CI */
switch (citype) { /* Check CI type */
- case CI_MRU:
- LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd MRU"))
+ case CI_MRU:
+ LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd MRU"));
if (!ao->neg_mru || /* Allow option? */
- cilen != sizeof (short)) { /* Check CI length */
- INCPTR(cilen, p); /* Skip rest of CI */
+ cilen != CILEN_SHORT) { /* Check CI length */
orc = CONFREJ; /* Reject CI */
break;
}
GETSHORT(cishort, p); /* Parse MRU */
- LCPDEBUG((LOG_INFO, "(%d)", cishort))
+ LCPDEBUG((LOG_INFO, "(%d)", cishort));
/*
* He must be able to receive at least our minimum.
@@ -717,131 +984,136 @@ int *len; /* Length of requested CIs */
*/
if (cishort < MINMRU) {
orc = CONFNAK; /* Nak CI */
- DECPTR(sizeof (short), p); /* Backup */
- PUTSHORT(MINMRU, p); /* Give him a hint */
+ if( !reject_if_disagree ){
+ DECPTR(sizeof (short), p); /* Backup */
+ PUTSHORT(MINMRU, p); /* Give him a hint */
+ }
break;
}
- ho->neg_mru = 1; /* Remember he sent and MRU */
+ ho->neg_mru = 1; /* Remember he sent MRU */
ho->mru = cishort; /* And remember value */
break;
- case CI_ASYNCMAP:
- LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd ASYNCMAP"))
+ case CI_ASYNCMAP:
+ LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd ASYNCMAP"));
if (!ao->neg_asyncmap ||
- cilen != sizeof (long)) {
- INCPTR(cilen, p);
+ cilen != CILEN_LONG) {
orc = CONFREJ;
break;
}
GETLONG(cilong, p);
- LCPDEBUG((LOG_INFO, "(%lx)", cilong))
+ LCPDEBUG((LOG_INFO, "(%lx)", cilong));
- /* XXX Accept anything he says */
-#if 0
/*
- * Asyncmap must be OR of two maps.
+ * Asyncmap must have set at least the bits
+ * which are set in lcp_allowoptions[unit].asyncmap.
*/
- if ((lcp_wantoptions[f->unit].neg_asyncmap &&
- cilong != (lcp_wantoptions[f->unit].asyncmap | cilong)) ||
- (!lcp_wantoptions[f->unit].neg_asyncmap &&
- cilong != 0xffffffff)) {
+ if ((ao->asyncmap & ~cilong) != 0) {
orc = CONFNAK;
- DECPTR(sizeof (long), p);
- PUTLONG(lcp_wantoptions[f->unit].neg_asyncmap ?
- lcp_wantoptions[f->unit].asyncmap | cilong :
- 0xffffffff, p);
+ if( !reject_if_disagree ){
+ DECPTR(sizeof (long), p);
+ PUTLONG(ao->asyncmap | cilong, p);
+ }
break;
}
-#endif
ho->neg_asyncmap = 1;
ho->asyncmap = cilong;
break;
- case CI_AUTHTYPE:
- if (cilen < sizeof (short) ||
- (!ao->neg_upap && !ao->neg_chap)) {
- LCPDEBUG((LOG_WARNING,
- "lcp_reqci: rcvd AUTHTYPE, rejecting ...!"))
- INCPTR(cilen, p);
- orc = CONFREJ;
- break;
+ case CI_AUTHTYPE:
+ LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd AUTHTYPE"));
+ if (cilen < CILEN_SHORT ||
+ !(ao->neg_upap || ao->neg_chap)) {
+ orc = CONFREJ;
+ break;
}
GETSHORT(cishort, p);
- LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd AUTHTYPE (%x)",
- cishort))
+ LCPDEBUG((LOG_INFO, "(%x)", cishort));
/*
* Authtype must be UPAP or CHAP.
+ *
+ * Note: if both ao->neg_upap and ao->neg_chap are set,
+ * and the peer sends a Configure-Request with two
+ * authenticate-protocol requests, one for CHAP and one
+ * for UPAP, then we will reject the second request.
+ * Whether we end up doing CHAP or UPAP depends then on
+ * the ordering of the CIs in the peer's Configure-Request.
*/
+
if (cishort == UPAP) {
- INCPTR(cilen - sizeof (u_short), p);
- if (!ao->neg_upap) { /* we don't want to do PAP */
- LCPDEBUG((LOG_INFO,
- "lcp_reqci: rcvd AUTHTYPE PAP, rejecting..."))
- orc = CONFREJ;
+ if (!ao->neg_upap || /* we don't want to do PAP */
+ ho->neg_chap || /* or we've already accepted CHAP */
+ cilen != CILEN_SHORT) {
+ LCPDEBUG((LOG_WARNING,
+ "lcp_reqci: rcvd AUTHTYPE PAP, rejecting..."));
+ orc = CONFREJ;
+ break;
+ }
+ ho->neg_upap = 1;
break;
- }
- ho->neg_upap = 1;
- break;
}
- else if (cishort == CHAP) {
- INCPTR(cilen - sizeof (u_short), p);
- if (!ao->neg_chap) { /* we don't want to do CHAP */
- LCPDEBUG((LOG_INFO,
- "lcp_reqci: rcvd AUTHTYPE CHAP, rejecting..."))
- orc = CONFREJ;
+ if (cishort == CHAP) {
+ if (!ao->neg_chap || /* we don't want to do CHAP */
+ ho->neg_upap || /* or we've already accepted UPAP */
+ cilen != CILEN_CHAP) {
+ LCPDEBUG((LOG_INFO,
+ "lcp_reqci: rcvd AUTHTYPE CHAP, rejecting..."));
+ orc = CONFREJ;
+ break;
+ }
+ GETCHAR(cichar, p); /* get digest type*/
+ if (cichar != ao->chap_mdtype) {
+ orc = CONFNAK;
+ if( !reject_if_disagree ){
+ DECPTR(sizeof (u_char), p);
+ PUTCHAR(ao->chap_mdtype, p);
+ }
+ break;
+ }
+ ho->chap_mdtype = cichar; /* save md type */
+ ho->neg_chap = 1;
break;
- }
- GETCHAR(cichar, p); /* get digest type*/
- if (cichar != ao->chap_mdtype) {
- DECPTR(sizeof (u_char), p);
- orc = CONFNAK;
- PUTCHAR(ao->chap_mdtype, p);
- INCPTR(cilen - sizeof(u_char), p);
- break;
- }
- ho->chap_mdtype = cichar; /* save md type */
- GETCHAR(cichar, p); /* get callback type*/
- if (cichar != ao->chap_callback) { /* we don't callback yet */
- DECPTR(sizeof (u_char), p);
- orc = CONFNAK;
- PUTCHAR(CHAP_NOCALLBACK, p);
- INCPTR(cilen - sizeof(u_char), p);
+ }
+
+ /*
+ * We don't recognize the protocol they're asking for.
+ * Reject it.
+ */
+ orc = CONFREJ;
+ break;
+
+ case CI_QUALITY:
+ LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd QUALITY"));
+ if (!ao->neg_lqr ||
+ cilen != CILEN_LQR) {
+ orc = CONFREJ;
break;
- }
- ho->chap_callback = cichar; /* save callback */
- ho->neg_chap = 1;
- break;
}
- else {
- DECPTR(sizeof (short), p);
- orc = CONFNAK;
- if (ao->neg_chap) { /* We prefer CHAP */
- PUTSHORT(CHAP, p);
- }
- else
- if (ao->neg_upap) {
- PUTSHORT(CHAP, p);
- }
- else {
- syslog(LOG_ERR, "Coding botch in lcp_reqci authnak. This shouldn't happen.");
- exit(1);
- }
- INCPTR(cilen - sizeof (u_short), p);
- break;
+
+ GETSHORT(cishort, p);
+ GETLONG(cilong, p);
+ LCPDEBUG((LOG_INFO, "(%x %lx)", cishort, cilong));
+ if (cishort != LQR) {
+ orc = CONFREJ;
+ break;
}
+ /*
+ * Check the reporting period.
+ * XXX When should we Nak this, and what with?
+ */
+ break;
- case CI_MAGICNUMBER:
- LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd MAGICNUMBER"))
- if (!ao->neg_magicnumber ||
- cilen != sizeof (long)) {
- INCPTR(cilen, p);
+ case CI_MAGICNUMBER:
+ LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd MAGICNUMBER"));
+ if (!(ao->neg_magicnumber || go->neg_magicnumber) ||
+ cilen != CILEN_LONG) {
orc = CONFREJ;
break;
}
GETLONG(cilong, p);
- LCPDEBUG((LOG_INFO, "(%lx)", cilong))
+ LCPDEBUG((LOG_INFO, "(%lx)", cilong));
/*
* He must have a different magic number.
@@ -859,50 +1131,49 @@ int *len; /* Length of requested CIs */
break;
- case CI_PCOMPRESSION:
- LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd PCOMPRESSION"))
+ case CI_PCOMPRESSION:
+ LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd PCOMPRESSION"));
if (!ao->neg_pcompression ||
- cilen != 0) {
- INCPTR(cilen, p);
+ cilen != CILEN_VOID) {
orc = CONFREJ;
break;
}
ho->neg_pcompression = 1;
break;
- case CI_ACCOMPRESSION:
- LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd ACCOMPRESSION"))
+ case CI_ACCOMPRESSION:
+ LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd ACCOMPRESSION"));
if (!ao->neg_accompression ||
- cilen != 0) {
- INCPTR(cilen, p);
+ cilen != CILEN_VOID) {
orc = CONFREJ;
break;
}
ho->neg_accompression = 1;
break;
- default:
+ default:
LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd unknown option %d",
- citype))
- INCPTR(cilen, p);
+ citype));
orc = CONFREJ;
break;
}
- cilen += 2; /* Adjust cilen whole CI */
endswitch:
- LCPDEBUG((LOG_INFO, " (%s)",
- orc == CONFACK ? "ACK" : (orc == CONFNAK ? "NAK" : "REJ")))
+ LCPDEBUG((LOG_INFO, " (%s)", CODENAME(orc)));
if (orc == CONFACK && /* Good CI */
rc != CONFACK) /* but prior CI wasnt? */
continue; /* Don't send this one */
if (orc == CONFNAK) { /* Nak this CI? */
- if (rc == CONFREJ) /* Rejecting prior CI? */
- continue; /* Don't send this one */
- if (rc == CONFACK) { /* Ack'd all prior CIs? */
- rc = CONFNAK; /* Not anymore... */
- ucp = inp; /* Backup */
+ if (reject_if_disagree) /* Getting fed up with sending NAKs? */
+ orc = CONFREJ; /* Get tough if so */
+ else {
+ if (rc == CONFREJ) /* Rejecting prior CI? */
+ continue; /* Don't send this one */
+ if (rc == CONFACK) { /* Ack'd all prior CIs? */
+ rc = CONFNAK; /* Not anymore... */
+ ucp = inp; /* Backup */
+ }
}
}
if (orc == CONFREJ && /* Reject this CI */
@@ -916,15 +1187,14 @@ endswitch:
}
/*
- * XXX If we wanted to send additional NAKs (for unsent CIs), the
+ * If we wanted to send additional NAKs (for unsent CIs), the
* code would go here. This must be done with care since it might
- * require a longer packet than we received.
+ * require a longer packet than we received. At present there
+ * are no cases where we want to ask the peer to negotiate an option.
*/
- *len = ucp - inp; /* Compute output length */
- LCPDEBUG((LOG_INFO, "lcp_reqci: returning %s.",
- rc == CONFACK ? "CONFACK" :
- rc == CONFNAK ? "CONFNAK" : "CONFREJ"))
+ *lenp = ucp - inp; /* Compute output length */
+ LCPDEBUG((LOG_INFO, "lcp_reqci: returning CONF%s.", CODENAME(rc)));
return (rc); /* Return final code */
}
@@ -935,43 +1205,35 @@ endswitch:
* Start UPAP, IPCP, etc.
*/
static void
- lcp_up(f)
-fsm *f;
+lcp_up(f)
+ fsm *f;
{
+ lcp_options *wo = &lcp_wantoptions[f->unit];
lcp_options *ho = &lcp_hisoptions[f->unit];
lcp_options *go = &lcp_gotoptions[f->unit];
- int auth = 0;
+ lcp_options *ao = &lcp_allowoptions[f->unit];
+
+ /*
+ * Set our MTU to the smaller of the MTU we wanted and
+ * the MRU our peer wanted. If we negotiated an MRU,
+ * set our MRU to the larger of value we wanted and
+ * the value we got in the negotiation.
+ */
+ ppp_send_config(f->unit, (ho->neg_mru? MIN(ao->mru, ho->mru): MTU),
+ (ho->neg_asyncmap? ho->asyncmap: 0xffffffff),
+ ho->neg_pcompression, ho->neg_accompression);
+ ppp_recv_config(f->unit, (go->neg_mru? MAX(wo->mru, go->mru): MTU),
+ (go->neg_asyncmap? go->asyncmap: 0xffffffff),
+ go->neg_pcompression, go->neg_accompression);
if (ho->neg_mru)
- SIFMTU(f->unit, ho->mru);
- if (ho->neg_asyncmap)
- SIFASYNCMAP(f->unit, ho->asyncmap);
- if (ho->neg_pcompression)
- SIFPCOMPRESSION(f->unit);
- if (ho->neg_accompression)
- SIFACCOMPRESSION(f->unit);
- SIFUP(f->unit); /* Bring the interface up (set IFF_UP) */
+ peer_mru[f->unit] = ho->mru;
+
ChapLowerUp(f->unit); /* Enable CHAP */
upap_lowerup(f->unit); /* Enable UPAP */
ipcp_lowerup(f->unit); /* Enable IPCP */
- if (go->neg_chap) {
- ChapAuthPeer(f->unit);
- auth = 1;
- }
- if (ho->neg_chap) {
- ChapAuthWithPeer(f->unit);
- auth = 1;
- }
- if (go->neg_upap) {
- upap_authpeer(f->unit);
- auth = 1;
- }
- if (ho->neg_upap) {
- upap_authwithpeer(f->unit);
- auth = 1;
- }
- if (!auth)
- ipcp_activeopen(f->unit);
+
+ link_established(f->unit);
}
@@ -981,36 +1243,39 @@ fsm *f;
* Alert other protocols.
*/
static void
- lcp_down(f)
-fsm *f;
+lcp_down(f)
+ fsm *f;
{
- ipcp_lowerdown(f->unit);
- SIFDOWN(f->unit);
- SIFMTU(f->unit, MTU);
- SIFASYNCMAP(f->unit, 0xffffffff);
- CIFPCOMPRESSION(f->unit);
- CIFACCOMPRESSION(f->unit);
- ChapLowerDown(f->unit);
- upap_lowerdown(f->unit);
+ ipcp_lowerdown(f->unit);
+ ChapLowerDown(f->unit);
+ upap_lowerdown(f->unit);
+
+ sifdown(f->unit);
+ ppp_send_config(f->unit, MTU, 0xffffffff, 0, 0);
+ ppp_recv_config(f->unit, MTU, 0, 0, 0);
+ peer_mru[f->unit] = MTU;
+ syslog(LOG_NOTICE, "Connection terminated.");
}
/*
- * lcp_closed - LCP has CLOSED.
- *
- * Alert other protocols.
+ * lcp_starting - LCP needs the lower layer up.
*/
static void
- lcp_closed(f)
-fsm *f;
+lcp_starting(f)
+ fsm *f;
{
- if (lcp_wantoptions[f->unit].restart) {
- if (lcp_wantoptions[f->unit].passive)
- lcp_passiveopen(f->unit); /* Start protocol in passive mode */
- else
- lcp_activeopen(f->unit); /* Start protocol in active mode */
- }
- else {
- EXIT(f->unit);
- }
+ link_required(f->unit);
+}
+
+
+/*
+ * lcp_finished - LCP has finished with the lower layer.
+ */
+static void
+lcp_finished(f)
+ fsm *f;
+{
+ link_terminated(f->unit);
}
+