summaryrefslogtreecommitdiffstats
path: root/usr.sbin/ppp/lcp.c
diff options
context:
space:
mode:
authoramurai <amurai@FreeBSD.org>1995-01-31 06:29:58 +0000
committeramurai <amurai@FreeBSD.org>1995-01-31 06:29:58 +0000
commit21ef2761fd1e5a4beb483da8bddf767d36540dce (patch)
tree3aecd1251d1647032ad1455f304eaeeaab4987d0 /usr.sbin/ppp/lcp.c
parent0487956fcf018d602bfe99b0e3398c6f4d55680a (diff)
downloadFreeBSD-src-21ef2761fd1e5a4beb483da8bddf767d36540dce.zip
FreeBSD-src-21ef2761fd1e5a4beb483da8bddf767d36540dce.tar.gz
Diffstat (limited to 'usr.sbin/ppp/lcp.c')
-rw-r--r--usr.sbin/ppp/lcp.c656
1 files changed, 656 insertions, 0 deletions
diff --git a/usr.sbin/ppp/lcp.c b/usr.sbin/ppp/lcp.c
new file mode 100644
index 0000000..175e7c6
--- /dev/null
+++ b/usr.sbin/ppp/lcp.c
@@ -0,0 +1,656 @@
+/*
+ * PPP Link Control Protocol (LCP) Module
+ *
+ * Written by Toshiharu OHNO (tony-o@iij.ad.jp)
+ *
+ * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Internet Initiative Japan, Inc. The name of the
+ * IIJ may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id:$
+ *
+ * TODO:
+ * o Validate magic number received from peer.
+ * o Limit data field length by MRU
+ */
+#if __FreeBSD__ >=2
+#include <sys/time.h>
+#endif
+#include "fsm.h"
+#include "lcp.h"
+#include "ipcp.h"
+#include "lcpproto.h"
+#include "os.h"
+#include "hdlc.h"
+#include "lqr.h"
+#include "phase.h"
+#include "vars.h"
+
+extern void IpcpUp();
+extern void IpcpOpen();
+extern void SendPapChallenge();
+extern void SendChapChallenge();
+extern void SetLinkParams(struct lcpstate *);
+extern void Prompt();
+extern void StopIdleTimer();
+extern void HdlcInit();
+extern void OsLinkdown();
+extern void Cleanup();
+
+struct lcpstate LcpInfo;
+
+static void LcpSendConfigReq(struct fsm *);
+static void LcpSendTerminateReq(struct fsm *fp);
+static void LcpSendTerminateAck(struct fsm *fp);
+static void LcpDecodeConfig(struct mbuf *bp, int mode);
+static void LcpInitRestartCounter(struct fsm *);
+static void LcpLayerUp(struct fsm *);
+static void LcpLayerDown(struct fsm *);
+static void LcpLayerStart(struct fsm *);
+static void LcpLayerFinish(struct fsm *);
+
+extern int ModemSpeed();
+
+#define REJECTED(p, x) (p->his_reject & (1<<x))
+
+static char *cftypes[] = {
+ "???", "MRU", "ACCMAP", "AUTHPROTO", "QUALPROTO", "MAGICNUM",
+ "RESERVED", "PROTOCOMP", "ACFCOMP", "FCSALT", "SDP",
+};
+
+struct fsm LcpFsm = {
+ "LCP", /* Name of protocol */
+ PROTO_LCP, /* Protocol Number */
+ LCP_MAXCODE,
+ OPEN_ACTIVE,
+ ST_INITIAL, /* State of machine */
+ 0, 0, 0,
+
+ 0,
+ { 0, 0, 0, NULL, NULL, NULL },
+
+ LcpLayerUp,
+ LcpLayerDown,
+ LcpLayerStart,
+ LcpLayerFinish,
+ LcpInitRestartCounter,
+ LcpSendConfigReq,
+ LcpSendTerminateReq,
+ LcpSendTerminateAck,
+ LcpDecodeConfig,
+};
+
+static struct pppTimer LcpReportTimer;
+
+char *PhaseNames[] = {
+ "Dead", "Establish", "Authenticate", "Network", "Terminate"
+};
+
+void
+NewPhase(new)
+int new;
+{
+ struct lcpstate *lcp = &LcpInfo;
+
+ phase = new;
+ LogPrintf(LOG_PHASE, "Phase: %s\n", PhaseNames[phase]);
+ switch (phase) {
+ case PHASE_AUTHENTICATE:
+ lcp->auth_ineed = lcp->want_auth;
+ lcp->auth_iwait = lcp->his_auth;
+ LogPrintf(LOG_PHASE, " his = %x, mine = %x\n", lcp->his_auth, lcp->want_auth);
+ if (lcp->his_auth || lcp->want_auth) {
+ if (lcp->his_auth == PROTO_PAP)
+ SendPapChallenge();
+ if (lcp->want_auth == PROTO_CHAP)
+ SendChapChallenge();
+ } else
+ NewPhase(PHASE_NETWORK);
+ break;
+ case PHASE_NETWORK:
+ IpcpUp();
+ IpcpOpen();
+ CcpUp();
+ CcpOpen();
+ break;
+ case PHASE_DEAD:
+ if (mode & MODE_DIRECT)
+ Cleanup(EX_DEAD);
+ break;
+ }
+}
+
+static void
+LcpReportTime()
+{
+#ifdef VERBOSE
+ time_t t;
+
+ time(&t);
+ logprintf("%s", ctime(&t));
+#endif
+ StopTimer(&LcpReportTimer);
+ LcpReportTimer.state = TIMER_STOPPED;
+ StartTimer(&LcpReportTimer);
+ HdlcErrorCheck();
+}
+
+int
+ReportLcpStatus()
+{
+ struct lcpstate *lcp = &LcpInfo;
+ struct fsm *fp = &LcpFsm;
+
+ printf("%s [%s]\n", fp->name, StateNames[fp->state]);
+ printf(
+ " his side: MRU %d, ACCMAP %08x, PROTOCOMP %d, ACFCOMP %d MAGIC %08x\n",
+ lcp->his_mru, lcp->his_accmap, lcp->his_protocomp, lcp->his_acfcomp, lcp->his_magic);
+ printf(
+ " my side: MRU %d, ACCMAP %08x, PROTOCOMP %d, ACFCOMP %d MAGIC %08x\n",
+ lcp->want_mru, lcp->want_accmap, lcp->want_protocomp, lcp->want_acfcomp, lcp->want_magic);
+ printf("\nDefaults: MRU = %d, ACCMAP = %08x\t", VarMRU, VarAccmap);
+ printf("Open Mode: %s\n", (VarOpenMode == OPEN_ACTIVE)? "active" : "passive");
+ return(1);
+}
+
+/*
+ * Generate random number which will be used as magic number.
+ */
+u_long
+GenerateMagic()
+{
+ time_t tl;
+ struct timeval tval;
+
+ time(&tl);
+ gettimeofday(&tval, NULL);
+ tl += tval.tv_sec ^ tval.tv_usec + getppid();
+ tl *= getpid();
+ return(tl);
+}
+
+void
+LcpInit()
+{
+ struct lcpstate *lcp = &LcpInfo;
+
+ FsmInit(&LcpFsm);
+ HdlcInit();
+
+ bzero(lcp, sizeof(struct lcpstate));
+ lcp->want_mru = VarMRU;
+ lcp->his_mru = DEF_MRU;
+ lcp->his_accmap = 0xffffffff;
+ lcp->want_accmap = VarAccmap;
+ lcp->want_magic = GenerateMagic();
+ lcp->want_auth = lcp->his_auth = 0;
+ if (Enabled(ConfChap))
+ lcp->want_auth = PROTO_CHAP;
+ else if (Enabled(ConfPap))
+ lcp->want_auth = PROTO_PAP;
+ if (Enabled(ConfLqr)) lcp->want_lqrperiod = VarLqrTimeout * 100;
+ if (Enabled(ConfAcfcomp)) lcp->want_acfcomp = 1;
+ if (Enabled(ConfProtocomp)) lcp->want_protocomp = 1;
+ LcpFsm.maxconfig = 10;
+}
+
+static void
+LcpInitRestartCounter(fp)
+struct fsm *fp;
+{
+ fp->FsmTimer.load = 5 * SECTICKS;
+ fp->restart = 5;
+}
+
+void
+PutConfValue(cpp, types, type, len, val)
+u_char **cpp;
+char **types;
+u_char type;
+int len;
+u_long val;
+{
+ u_char *cp;
+
+ cp = *cpp;
+ *cp++ = type; *cp++ = len;
+ if (len == 6) {
+ if (type == TY_IPADDR) {
+ LogPrintf(LOG_LCP, " %s [%d] %s\n",
+ types[type], len, inet_ntoa(htonl(val)));
+ } else {
+ LogPrintf(LOG_LCP, " %s [%d] %08x\n", types[type], len, val);
+ }
+ *cp++ = (val >> 24) & 0377;
+ *cp++ = (val >> 16) & 0377;
+ } else
+ LogPrintf(LOG_LCP, " %s [%d] %d\n", types[type], len, val);
+ *cp++ = (val >> 8) & 0377;
+ *cp++ = val & 0377;
+ *cpp = cp;
+}
+
+static void
+LcpSendConfigReq(fp)
+struct fsm *fp;
+{
+ u_char *cp;
+ struct lcpstate *lcp = &LcpInfo;
+ struct lqrreq *req;
+
+ LogPrintf(LOG_LCP, "%s: SendConfigReq\n", fp->name);
+ cp = ReqBuff;
+ if (lcp->want_acfcomp && !REJECTED(lcp, TY_ACFCOMP)) {
+ *cp++ = TY_ACFCOMP; *cp++ = 2;
+ LogPrintf(LOG_LCP, " %s\n", cftypes[TY_ACFCOMP]);
+ }
+ if (lcp->want_protocomp && !REJECTED(lcp, TY_PROTOCOMP)) {
+ *cp++ = TY_PROTOCOMP; *cp++ = 2;
+ LogPrintf(LOG_LCP, " %s\n", cftypes[TY_PROTOCOMP]);
+ }
+ if (!REJECTED(lcp, TY_MRU))
+ PutConfValue(&cp, cftypes, TY_MRU, 4, lcp->want_mru);
+ if (!REJECTED(lcp, TY_ACCMAP))
+ PutConfValue(&cp, cftypes, TY_ACCMAP, 6, lcp->want_accmap);
+ if (lcp->want_magic && !REJECTED(lcp, TY_MAGICNUM))
+ PutConfValue(&cp, cftypes, TY_MAGICNUM, 6, lcp->want_magic);
+ if (lcp->want_lqrperiod && !REJECTED(lcp, TY_QUALPROTO)) {
+ req = (struct lqrreq *)cp;
+ req->type = TY_QUALPROTO; req->length = sizeof(struct lqrreq);
+ req->proto = htons(PROTO_LQR);
+ req->period = htonl(lcp->want_lqrperiod);
+ cp += sizeof(struct lqrreq);
+ LogPrintf(LOG_LCP, " %s (%d)\n", cftypes[TY_QUALPROTO], lcp->want_lqrperiod);
+ }
+ switch (lcp->want_auth) {
+ case PROTO_PAP:
+ PutConfValue(&cp, cftypes, TY_AUTHPROTO, 4, lcp->want_auth);
+ break;
+ case PROTO_CHAP:
+ PutConfValue(&cp, cftypes, TY_AUTHPROTO, 5, lcp->want_auth);
+ *cp++ = 5; /* Use MD5 */
+ break;
+ }
+ FsmOutput(fp, CODE_CONFIGREQ, fp->reqid++, ReqBuff, cp - ReqBuff);
+}
+
+void
+LcpSendProtoRej(option, count)
+u_char *option;
+int count;
+{
+ struct fsm *fp = &LcpFsm;
+
+ LogPrintf(LOG_LCP, "%s: SendProtoRej\n", fp->name);
+ FsmOutput(fp, CODE_PROTOREJ, fp->reqid, option, count);
+}
+
+static void
+LcpSendTerminateReq(fp)
+struct fsm *fp;
+{
+ /* Most thins are done in fsm layer. Nothing to to. */
+}
+
+static void
+LcpSendTerminateAck(fp)
+struct fsm *fp;
+{
+ LogPrintf(LOG_LCP, "%s: SendTerminateAck.\n", fp->name);
+ FsmOutput(fp, CODE_TERMACK, fp->reqid++, NULL, 0);
+}
+
+static void
+LcpLayerStart(fp)
+struct fsm *fp;
+{
+ LogPrintf(LOG_LCP, "%s: LayerStart\n", fp->name);
+ NewPhase(PHASE_ESTABLISH);
+}
+
+static void
+LcpLayerFinish(fp)
+struct fsm *fp;
+{
+#ifdef VERBOSE
+ fprintf(stderr, "%s: LayerFinish\r\n", fp->name);
+#endif
+ Prompt(1);
+ LogPrintf(LOG_LCP, "%s: LayerFinish\n", fp->name);
+#ifdef notdef
+ OsCloseLink(0);
+#else
+ OsCloseLink(1);
+#endif
+ NewPhase(PHASE_DEAD);
+ StopTimer(&LcpReportTimer);
+ StopIdleTimer();
+ OsInterfaceDown(0);
+}
+
+static void
+LcpLayerUp(fp)
+struct fsm *fp;
+{
+ LogPrintf(LOG_LCP, "%s: LayerUp\n", fp->name);
+ OsSetInterfaceParams(23, LcpInfo.his_mru, ModemSpeed());
+ SetLinkParams(&LcpInfo);
+
+ NewPhase(PHASE_AUTHENTICATE);
+
+ StartLqm();
+ StopTimer(&LcpReportTimer);
+ LcpReportTimer.state = TIMER_STOPPED;
+ LcpReportTimer.load = 60 * SECTICKS;
+ LcpReportTimer.func = LcpReportTime;
+ StartTimer(&LcpReportTimer);
+}
+
+static void
+LcpLayerDown(fp)
+struct fsm *fp;
+{
+ LogPrintf(LOG_LCP, "%s: LayerDown\n", fp->name);
+ OsLinkdown();
+ NewPhase(PHASE_TERMINATE);
+}
+
+void
+LcpUp()
+{
+ FsmUp(&LcpFsm);
+}
+
+void
+LcpDown()
+{
+ NewPhase(PHASE_DEAD);
+ FsmDown(&LcpFsm);
+}
+
+void
+LcpOpen(mode)
+int mode;
+{
+ LcpFsm.open_mode = mode;
+ FsmOpen(&LcpFsm);
+}
+
+void
+LcpClose()
+{
+ FsmClose(&LcpFsm);
+}
+
+/*
+ * XXX: Should validate option length
+ */
+static void
+LcpDecodeConfig(bp, mode)
+struct mbuf *bp;
+int mode;
+{
+ u_char *cp;
+ char *request;
+ int plen, type, length, mru;
+ u_long *lp, magic, accmap;
+ u_short *sp, proto;
+ struct lqrreq *req;
+
+ plen = plength(bp);
+
+ cp = MBUF_CTOP(bp);
+ ackp = AckBuff;
+ nakp = NakBuff;
+ rejp = RejBuff;
+
+ while (plen >= sizeof(struct fsmconfig)) {
+ type = *cp;
+ length = cp[1];
+ if (type <= TY_ACFCOMP)
+ request = cftypes[type];
+ else
+ request = "???";
+
+ switch (type) {
+ case TY_MRU:
+ sp = (u_short *)(cp + 2);
+ mru = htons(*sp);
+ LogPrintf(LOG_LCP, " %s %d\n", request, mru);
+
+ switch (mode) {
+ case MODE_REQ:
+ if (mru > MAX_MRU) {
+ *sp = htons(MAX_MRU);
+ bcopy(cp, nakp, 4); nakp += 4;
+ } else if (mru < MIN_MRU) {
+ *sp = htons(MIN_MRU);
+ bcopy(cp, nakp, 4); nakp += 4;
+ } else {
+ LcpInfo.his_mru = mru;
+ bcopy(cp, ackp, 4); ackp += 4;
+ }
+ break;
+ case MODE_NAK:
+ if (mru >= MIN_MRU || mru <= MAX_MRU)
+ LcpInfo.want_mru = mru;
+ break;
+ case MODE_REJ:
+ LcpInfo.his_reject |= (1 << type);
+ break;
+ }
+ break;
+ case TY_ACCMAP:
+ lp = (u_long *)(cp + 2);
+ accmap = htonl(*lp);
+ LogPrintf(LOG_LCP, " %s %08x\n", request, accmap);
+
+ switch (mode) {
+ case MODE_REQ:
+ LcpInfo.his_accmap = accmap;
+ bcopy(cp, ackp, 6); ackp += 6;
+ break;
+ case MODE_NAK:
+ LcpInfo.want_accmap = accmap;
+ break;
+ case MODE_REJ:
+ LcpInfo.his_reject |= (1 << type);
+ break;
+ }
+ break;
+ case TY_AUTHPROTO:
+ sp = (u_short *)(cp + 2);
+ proto = ntohs(*sp);
+ LogPrintf(LOG_LCP, " %s proto = %x\n", request, proto);
+
+ switch (mode) {
+ case MODE_REQ:
+ switch (proto) {
+ case PROTO_PAP:
+ if (length != 4) {
+ LogPrintf(LOG_LCP, " %s bad length (%d)\n", request, length);
+ goto reqreject;
+ }
+ if (Acceptable(ConfPap)) {
+ LcpInfo.his_auth = proto;
+ bcopy(cp, ackp, length); ackp += length;
+ } else if (Acceptable(ConfChap)) {
+ *nakp++ = *cp; *nakp++ = 5;
+ *nakp++ = (unsigned char)PROTO_CHAP >> 8;
+ *nakp++ = (unsigned char)PROTO_CHAP;
+ *nakp++ = 5;
+ } else
+ goto reqreject;
+ break;
+ case PROTO_CHAP:
+ if (length < 5) {
+ LogPrintf(LOG_LCP, " %s bad length (%d)\n", request, length);
+ goto reqreject;
+ }
+ if (Acceptable(ConfChap) && cp[4] == 5) {
+ LcpInfo.his_auth = proto;
+ bcopy(cp, ackp, length); ackp += length;
+ } else if (Acceptable(ConfPap)) {
+ *nakp++ = *cp; *nakp++ = 4;
+ *nakp++ = (unsigned char)PROTO_PAP >> 8;
+ *nakp++ = (unsigned char)PROTO_PAP;
+ } else
+ goto reqreject;
+ break;
+ default:
+ LogPrintf(LOG_LCP, " %s not implemented.\n", request);
+ goto reqreject;
+ }
+ break;
+ case MODE_NAK:
+ break;
+ case MODE_REJ:
+ LcpInfo.his_reject |= (1 << type);
+ break;
+ }
+ break;
+ case TY_QUALPROTO:
+ req = (struct lqrreq *)cp;
+ LogPrintf(LOG_LCP, " %s proto: %x, interval: %dms\n",
+ request, ntohs(req->proto), ntohl(req->period)*10);
+ switch (mode) {
+ case MODE_REQ:
+ if (ntohs(req->proto) != PROTO_LQR || !Acceptable(ConfLqr))
+ goto reqreject;
+ else {
+ LcpInfo.his_lqrperiod = ntohl(req->period);
+ if (LcpInfo.his_lqrperiod < 500)
+ LcpInfo.his_lqrperiod = 500;
+ req->period = htonl(LcpInfo.his_lqrperiod);
+ bcopy(cp, ackp, length); ackp += length;
+ }
+ break;
+ case MODE_NAK:
+ break;
+ case MODE_REJ:
+ LcpInfo.his_reject |= (1 << type);
+ break;
+ }
+ break;
+ case TY_MAGICNUM:
+ lp = (u_long *)(cp + 2);
+ magic = ntohl(*lp);
+ LogPrintf(LOG_LCP, " %s %08x\n", request, magic);
+
+ switch (mode) {
+ case MODE_REQ:
+ if (LcpInfo.want_magic) {
+ /* XXX: Shoud validate magic number */
+ if (magic == LcpInfo.want_magic)
+ logprintf("magic is same!! %x, %x, %x\n",
+ magic, LcpInfo.want_magic, LcpInfo.his_magic);
+ LcpInfo.his_magic = magic;
+ bcopy(cp, ackp, length); ackp += length;
+ } else {
+ LcpInfo.my_reject |= (1 << type);
+ goto reqreject;
+ }
+ break;
+ case MODE_NAK:
+ LogPrintf(LOG_LCP, " %s magic %08x has NAKed\n", request, magic);
+ LcpInfo.want_magic = GenerateMagic();
+ break;
+ case MODE_REJ:
+ LogPrintf(LOG_LCP, " %s magic has REJected\n", request);
+ LcpInfo.want_magic = 0;
+ LcpInfo.his_reject |= (1 << type);
+ break;
+ }
+ break;
+ case TY_PROTOCOMP:
+ LogPrintf(LOG_LCP, " %s\n", request);
+
+ switch (mode) {
+ case MODE_REQ:
+ if (Acceptable(ConfProtocomp)) {
+ LcpInfo.his_protocomp = 1;
+ bcopy(cp, ackp, 2); ackp += 2;
+ } else {
+#ifdef OLDMST
+ /*
+ * MorningStar before v1.3 needs NAK
+ */
+ bcopy(cp, nakp, 2); nakp += 2;
+#else
+ bcopy(cp, rejp, 2); rejp += 2;
+ LcpInfo.my_reject |= (1 << type);
+#endif
+ }
+ break;
+ case MODE_NAK:
+ case MODE_REJ:
+ LcpInfo.want_protocomp = 0;
+ LcpInfo.his_reject |= (1 << type);
+ break;
+ }
+ break;
+ case TY_ACFCOMP:
+ LogPrintf(LOG_LCP, " %s\n", request);
+ switch (mode) {
+ case MODE_REQ:
+ if (Acceptable(ConfAcfcomp)) {
+ LcpInfo.his_acfcomp = 1;
+ bcopy(cp, ackp, 2);
+ ackp += 2;
+ } else {
+#ifdef OLDMST
+ /*
+ * MorningStar before v1.3 needs NAK
+ */
+ bcopy(cp, nakp, 2);
+ nakp += 2;
+#else
+ bcopy(cp, rejp, 2);
+ rejp += 2;
+ LcpInfo.my_reject |= (1 << type);
+#endif
+ }
+ break;
+ case MODE_NAK:
+ case MODE_REJ:
+ LcpInfo.want_acfcomp = 0;
+ LcpInfo.his_reject |= (1 << type);
+ break;
+ }
+ break;
+ case TY_SDP:
+ LogPrintf(LOG_LCP, " %s\n", request);
+ switch (mode) {
+ case MODE_REQ:
+ case MODE_NAK:
+ case MODE_REJ:
+ break;
+ }
+ break;
+ default:
+reqreject:
+ bcopy(cp, rejp, length);
+ rejp += length;
+ LcpInfo.my_reject |= (1 << type);
+ break;
+ }
+ plen -= length;
+ cp += length;
+ }
+}
+
+void
+LcpInput(struct mbuf *bp)
+{
+ FsmInput(&LcpFsm, bp);
+}
OpenPOWER on IntegriCloud