summaryrefslogtreecommitdiffstats
path: root/usr.sbin/ppp
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
parent0487956fcf018d602bfe99b0e3398c6f4d55680a (diff)
downloadFreeBSD-src-21ef2761fd1e5a4beb483da8bddf767d36540dce.zip
FreeBSD-src-21ef2761fd1e5a4beb483da8bddf767d36540dce.tar.gz
Diffstat (limited to 'usr.sbin/ppp')
-rw-r--r--usr.sbin/ppp/Makefile12
-rw-r--r--usr.sbin/ppp/async.c185
-rw-r--r--usr.sbin/ppp/auth.c112
-rw-r--r--usr.sbin/ppp/ccp.c281
-rw-r--r--usr.sbin/ppp/ccp.h52
-rw-r--r--usr.sbin/ppp/chap.c259
-rw-r--r--usr.sbin/ppp/chap.h32
-rw-r--r--usr.sbin/ppp/chat.c377
-rw-r--r--usr.sbin/ppp/command.c807
-rw-r--r--usr.sbin/ppp/command.h30
-rw-r--r--usr.sbin/ppp/defs.h77
-rw-r--r--usr.sbin/ppp/filter.c475
-rw-r--r--usr.sbin/ppp/filter.h77
-rw-r--r--usr.sbin/ppp/fsm.c802
-rw-r--r--usr.sbin/ppp/fsm.h134
-rw-r--r--usr.sbin/ppp/global.h51
-rw-r--r--usr.sbin/ppp/hdlc.c378
-rw-r--r--usr.sbin/ppp/hdlc.h58
-rw-r--r--usr.sbin/ppp/ip.c398
-rw-r--r--usr.sbin/ppp/ipcp.c459
-rw-r--r--usr.sbin/ppp/ipcp.h62
-rw-r--r--usr.sbin/ppp/lcp.c656
-rw-r--r--usr.sbin/ppp/lcp.h83
-rw-r--r--usr.sbin/ppp/lcpproto.h52
-rw-r--r--usr.sbin/ppp/log.c223
-rw-r--r--usr.sbin/ppp/log.h53
-rw-r--r--usr.sbin/ppp/lqr.c259
-rw-r--r--usr.sbin/ppp/lqr.h66
-rw-r--r--usr.sbin/ppp/main.c693
-rw-r--r--usr.sbin/ppp/mbuf.c187
-rw-r--r--usr.sbin/ppp/mbuf.h67
-rw-r--r--usr.sbin/ppp/md5.h38
-rw-r--r--usr.sbin/ppp/md5c.c338
-rw-r--r--usr.sbin/ppp/modem.c591
-rw-r--r--usr.sbin/ppp/modem.h37
-rw-r--r--usr.sbin/ppp/os.c341
-rw-r--r--usr.sbin/ppp/os.h34
-rw-r--r--usr.sbin/ppp/pap.c163
-rw-r--r--usr.sbin/ppp/pap.h29
-rw-r--r--usr.sbin/ppp/pathnames.h50
-rw-r--r--usr.sbin/ppp/phase.h36
-rw-r--r--usr.sbin/ppp/ppp.8492
-rw-r--r--usr.sbin/ppp/pred.c237
-rw-r--r--usr.sbin/ppp/route.c392
-rw-r--r--usr.sbin/ppp/slcompress.c589
-rw-r--r--usr.sbin/ppp/slcompress.h142
-rw-r--r--usr.sbin/ppp/systems.c215
-rw-r--r--usr.sbin/ppp/timeout.h49
-rw-r--r--usr.sbin/ppp/timer.c151
-rw-r--r--usr.sbin/ppp/uucplock.c112
-rw-r--r--usr.sbin/ppp/vars.c153
-rw-r--r--usr.sbin/ppp/vars.h86
-rw-r--r--usr.sbin/ppp/vjcomp.c145
53 files changed, 11877 insertions, 0 deletions
diff --git a/usr.sbin/ppp/Makefile b/usr.sbin/ppp/Makefile
new file mode 100644
index 0000000..cc16a42
--- /dev/null
+++ b/usr.sbin/ppp/Makefile
@@ -0,0 +1,12 @@
+# $Id:$
+
+PROG= ppp
+SRCS= async.c auth.c ccp.c chap.c chat.c command.c filter.c fsm.c hdlc.c \
+ ip.c ipcp.c lcp.c lqr.c log.c main.c mbuf.c md5c.c modem.c os.c \
+ pap.c pred.c route.c slcompress.c timer.c systems.c uucplock.c vars.c \
+ vjcomp.c
+MAN8= ppp.8
+BINMODE=4555
+BINOWN= root
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/ppp/async.c b/usr.sbin/ppp/async.c
new file mode 100644
index 0000000..d518162
--- /dev/null
+++ b/usr.sbin/ppp/async.c
@@ -0,0 +1,185 @@
+/*
+ * PPP Async HDLC 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:$
+ *
+ */
+#include "fsm.h"
+#include "hdlc.h"
+#include "lcp.h"
+#include "lcpproto.h"
+#include "modem.h"
+
+#define HDLCSIZE (MAX_MRU*2+6)
+
+struct async_state {
+ int mode;
+ int length;
+ struct mbuf *hpacket;
+ u_char hbuff[HDLCSIZE]; /* recv buffer */
+ u_char xbuff[HDLCSIZE]; /* xmit buffer */
+ u_long my_accmap;
+ u_long his_accmap;
+} AsyncState;
+
+#define MODE_HUNT 0x01
+#define MODE_ESC 0x02
+
+void
+AsyncInit()
+{
+ struct async_state *stp = &AsyncState;
+
+ stp->mode = MODE_HUNT;
+ stp->my_accmap = stp->his_accmap = 0xffffffff;
+}
+
+void
+SetLinkParams(lcp)
+struct lcpstate *lcp;
+{
+ struct async_state *stp = &AsyncState;
+
+ stp->my_accmap = lcp->want_accmap;
+ stp->his_accmap = lcp->his_accmap;
+}
+
+/*
+ * Encode into async HDLC byte code if necessary
+ */
+static void
+HdlcPutByte(cp, c, proto)
+u_char **cp;
+u_char c;
+int proto;
+{
+ u_char *wp;
+
+ wp = *cp;
+ if ((c < 0x20 && (proto == PROTO_LCP || (AsyncState.his_accmap & (1<<c))))
+ || (c == HDLC_ESC) || (c == HDLC_SYN)) {
+ *wp++ = HDLC_ESC;
+ c ^= HDLC_XOR;
+ }
+ if (EscMap[32] && EscMap[c >> 3] & (c&7)) {
+ *wp++ = HDLC_ESC;
+ c ^= HDLC_XOR;
+ }
+ *wp++ = c;
+ *cp = wp;
+}
+
+void
+AsyncOutput(pri, bp, proto)
+int pri;
+struct mbuf *bp;
+int proto;
+{
+ struct async_state *hs = &AsyncState;
+ u_char *cp, *sp, *ep;
+ struct mbuf *wp;
+ int cnt;
+
+ if (plength(bp) > HDLCSIZE) {
+ pfree(bp);
+ return;
+ }
+ cp = hs->xbuff;
+ ep = cp + HDLCSIZE - 10;
+ wp = bp;
+ *cp ++ = HDLC_SYN;
+ while (wp) {
+ sp = MBUF_CTOP(wp);
+ for (cnt = wp->cnt; cnt > 0; cnt--) {
+ HdlcPutByte(&cp, *sp++, proto);
+ if (cp >= ep) {
+ pfree(bp);
+ return;
+ }
+ }
+ wp = wp->next;
+ }
+ *cp ++ = HDLC_SYN;
+
+ cnt = cp - hs->xbuff;
+ LogDumpBuff(LOG_ASYNC, "WriteModem", hs->xbuff, cnt);
+ WriteModem(pri, (char *)hs->xbuff, cnt);
+ OsAddOutOctets(cnt);
+ pfree(bp);
+}
+
+struct mbuf *
+AsyncDecode(c)
+u_char c;
+{
+ struct async_state *hs = &AsyncState;
+ struct mbuf *bp;
+
+ if ((hs->mode & MODE_HUNT) && c != HDLC_SYN)
+ return(NULLBUFF);
+
+ switch (c) {
+ case HDLC_SYN:
+ hs->mode &= ~MODE_HUNT;
+ if (hs->length) { /* packet is ready. */
+ bp = mballoc(hs->length, MB_ASYNC);
+ mbwrite(bp, hs->hbuff, hs->length);
+ hs->length = 0;
+ return(bp);
+ }
+ break;
+ case HDLC_ESC:
+ if (!(hs->mode & MODE_ESC)) {
+ hs->mode |= MODE_ESC;
+ break;
+ }
+ /* Fall into ... */
+ default:
+ if (hs->length >= HDLCSIZE) {
+ /* packet is too large, discard it */
+ logprintf("too large, diacarding.\n");
+ hs->length = 0;
+ hs->mode = MODE_HUNT;
+ break;
+ }
+ if (hs->mode & MODE_ESC) {
+ c ^= HDLC_XOR;
+ hs->mode &= ~MODE_ESC;
+ }
+ hs->hbuff[hs->length++] = c;
+ break;
+ }
+ return NULLBUFF;
+}
+
+void
+AsyncInput(buff, cnt)
+u_char *buff;
+int cnt;
+{
+ struct mbuf *bp;
+
+ OsAddInOctets(cnt);
+ while (cnt > 0) {
+ bp = AsyncDecode(*buff++);
+ if (bp)
+ HdlcInput(bp);
+ cnt--;
+ }
+}
diff --git a/usr.sbin/ppp/auth.c b/usr.sbin/ppp/auth.c
new file mode 100644
index 0000000..d6a5f72
--- /dev/null
+++ b/usr.sbin/ppp/auth.c
@@ -0,0 +1,112 @@
+/*
+ * PPP Secret Key Module
+ *
+ * Written by Toshiharu OHNO (tony-o@iij.ad.jp)
+ *
+ * Copyright (C) 1994, 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 Imprement check against with registerd IP addresses.
+ */
+#include "fsm.h"
+#include "ipcp.h"
+
+extern FILE *OpenSecret();
+extern void CloseSecret();
+
+int
+AuthValidate(fname, system, key)
+char *fname, *system, *key;
+{
+ FILE *fp;
+ int n;
+ char *vector[20];
+ char buff[200];
+ char passwd[100];
+
+ fp = OpenSecret(fname);
+ if (fp == NULL)
+ return(0);
+ while (fgets(buff, sizeof(buff), fp)) {
+ if (buff[0] == '#')
+ continue;
+ buff[strlen(buff)-1] = 0;
+ bzero(vector, sizeof(vector));
+ n = MakeArgs(buff, &vector);
+ if (n < 2)
+ continue;
+ if (strcmp(vector[0], system) == 0) {
+ ExpandString(vector[1], passwd, 0);
+ if (strcmp(passwd, key) == 0) {
+ CloseSecret(fp);
+ bzero(&DefHisAddress, sizeof(DefHisAddress));
+ n -= 2;
+ if (n > 0) {
+ ParseAddr(n--, &vector[2],
+ &DefHisAddress.ipaddr, &DefHisAddress.mask, &DefHisAddress.width);
+ }
+ IpcpInit();
+ return(1); /* Valid */
+ }
+ }
+ }
+ CloseSecret(fp);
+ return(0); /* Invalid */
+}
+
+char *
+AuthGetSecret(fname, system, len, setaddr)
+char *fname, *system;
+int len, setaddr;
+{
+ FILE *fp;
+ int n;
+ char *vector[20];
+ char buff[200];
+ static char passwd[100];
+
+ fp = OpenSecret(fname);
+ if (fp == NULL)
+ return(NULL);
+ while (fgets(buff, sizeof(buff), fp)) {
+ if (buff[0] == '#')
+ continue;
+ buff[strlen(buff)-1] = 0;
+ bzero(vector, sizeof(vector));
+ n = MakeArgs(buff, &vector);
+ if (n < 2)
+ continue;
+ if (strlen(vector[0]) == len && strncmp(vector[0], system, len) == 0) {
+ ExpandString(vector[1], passwd, 0);
+ if (setaddr) {
+ bzero(&DefHisAddress, sizeof(DefHisAddress));
+ }
+ n -= 2;
+ if (n > 0 && setaddr) {
+#ifdef DEBUG
+ LogPrintf(LOG_LCP, "*** n = %d, %s\n", n, vector[2]);
+#endif
+ ParseAddr(n--, &vector[2],
+ &DefHisAddress.ipaddr, &DefHisAddress.mask, &DefHisAddress.width);
+ IpcpInit();
+ }
+ return(passwd);
+ }
+ }
+ CloseSecret(fp);
+ return(NULL); /* Invalid */
+}
diff --git a/usr.sbin/ppp/ccp.c b/usr.sbin/ppp/ccp.c
new file mode 100644
index 0000000..ca2e1ac
--- /dev/null
+++ b/usr.sbin/ppp/ccp.c
@@ -0,0 +1,281 @@
+/*
+ * PPP Compression Control Protocol (CCP) Module
+ *
+ * Written by Toshiharu OHNO (tony-o@iij.ad.jp)
+ *
+ * Copyright (C) 1994, 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 Support other compression protocols
+ */
+#include "fsm.h"
+#include "lcpproto.h"
+#include "lcp.h"
+#include "ccp.h"
+#include "phase.h"
+#include "vars.h"
+
+extern void PutConfValue();
+
+struct ccpstate CcpInfo;
+
+static void CcpSendConfigReq(struct fsm *);
+static void CcpSendTerminateReq(struct fsm *fp);
+static void CcpSendTerminateAck(struct fsm *fp);
+static void CcpDecodeConfig(struct mbuf *bp, int mode);
+static void CcpLayerStart(struct fsm *);
+static void CcpLayerFinish(struct fsm *);
+static void CcpLayerUp(struct fsm *);
+static void CcpLayerDown(struct fsm *);
+static void CcpInitRestartCounter(struct fsm *);
+
+#define REJECTED(p, x) (p->his_reject & (1<<x))
+
+struct fsm CcpFsm = {
+ "CCP",
+ PROTO_CCP,
+ CCP_MAXCODE,
+ OPEN_ACTIVE,
+ ST_INITIAL,
+ 0, 0, 0,
+
+ 0,
+ { 0, 0, 0, NULL, NULL, NULL },
+
+ CcpLayerUp,
+ CcpLayerDown,
+ CcpLayerStart,
+ CcpLayerFinish,
+ CcpInitRestartCounter,
+ CcpSendConfigReq,
+ CcpSendTerminateReq,
+ CcpSendTerminateAck,
+ CcpDecodeConfig,
+};
+
+static char *cftypes[] = {
+/* 0 */ "OUI", "PRED1", "PRED2", "PUDDLE",
+/* 4 */ "???", "???", "???", "???",
+/* 8 */ "???", "???", "???", "???",
+/* 12 */ "???", "???", "???", "???",
+/* 16 */ "HWPPC", "STAC", "MSPPC", "GAND",
+/* 20 */ "V42BIS", "BSD",
+};
+
+void
+ReportCcpStatus()
+{
+ struct ccpstate *icp = &CcpInfo;
+ struct fsm *fp = &CcpFsm;
+
+ printf("%s [%s]\n", fp->name, StateNames[fp->state]);
+ printf("myproto = %s, hisproto = %s\n",
+ cftypes[icp->want_proto], cftypes[icp->his_proto]);
+ printf("Input: %d --> %d, Output: %d --> %d\n",
+ icp->orgin, icp->compin, icp->orgout, icp->compout);
+}
+
+void
+CcpInit()
+{
+ struct ccpstate *icp = &CcpInfo;
+
+ FsmInit(&CcpFsm);
+ bzero(icp, sizeof(struct ccpstate));
+ if (Enabled(ConfPred1))
+ icp->want_proto = TY_PRED1;
+ CcpFsm.maxconfig = 10;
+}
+
+static void
+CcpInitRestartCounter(fp)
+struct fsm *fp;
+{
+ fp->FsmTimer.load = 3 * SECTICKS;
+ fp->restart = 5;
+}
+
+static void
+CcpSendConfigReq(fp)
+struct fsm *fp;
+{
+ u_char *cp;
+ struct ccpstate *icp = &CcpInfo;
+
+ cp = ReqBuff;
+ LogPrintf(LOG_LCP, "%s: SendConfigReq\n", fp->name);
+ if (icp->want_proto && !REJECTED(icp, TY_PRED1)) {
+ *cp++ = TY_PRED1; *cp++ = 2;
+ }
+ FsmOutput(fp, CODE_CONFIGREQ, fp->reqid++, ReqBuff, cp - ReqBuff);
+}
+
+void
+CcpSendResetReq(fp)
+struct fsm *fp;
+{
+ Pred1Init(1); /* Initialize Input part */
+ LogPrintf(LOG_LCP, "%s: SendResetReq\n", fp->name);
+ FsmOutput(fp, CODE_RESETREQ, fp->reqid, NULL, 0);
+}
+
+static void
+CcpSendTerminateReq(fp)
+struct fsm *fp;
+{
+ /* XXX: No code yet */
+}
+
+static void
+CcpSendTerminateAck(fp)
+struct fsm *fp;
+{
+ LogPrintf(LOG_LCP, " %s: SendTerminateAck\n", fp->name);
+ FsmOutput(fp, CODE_TERMACK, fp->reqid++, NULL, 0);
+}
+
+void
+CcpRecvResetReq(fp)
+struct fsm *fp;
+{
+ Pred1Init(2); /* Initialize Output part */
+}
+
+static void
+CcpLayerStart(fp)
+struct fsm *fp;
+{
+ LogPrintf(LOG_LCP, "%s: LayerStart.\n", fp->name);
+}
+
+static void
+CcpLayerFinish(fp)
+struct fsm *fp;
+{
+ LogPrintf(LOG_LCP, "%s: LayerFinish.\n", fp->name);
+}
+
+static void
+CcpLayerDown(fp)
+struct fsm *fp;
+{
+ LogPrintf(LOG_LCP, "%s: LayerDown.\n", fp->name);
+}
+
+/*
+ * Called when CCP has reached to OPEN state
+ */
+static void
+CcpLayerUp(fp)
+struct fsm *fp;
+{
+#ifdef VERBOSE
+ fprintf(stderr, "%s: LayerUp(%d).\r\n", fp->name, fp->state);
+#endif
+ LogPrintf(LOG_LCP, "%s: LayerUp.\n", fp->name);
+ LogPrintf(LOG_LCP, "myproto = %d, hisproto = %d\n",
+ CcpInfo.want_proto, CcpInfo.his_proto);
+ Pred1Init(3); /* Initialize Input and Output */
+}
+
+void
+CcpUp()
+{
+ FsmUp(&CcpFsm);
+ LogPrintf(LOG_LCP, "CCP Up event!!\n");
+}
+
+void
+CcpOpen()
+{
+ if (Enabled(ConfPred1))
+ FsmOpen(&CcpFsm);
+}
+
+static void
+CcpDecodeConfig(bp, mode)
+struct mbuf *bp;
+int mode;
+{
+ u_char *cp;
+ int plen, type, length;
+ u_long *lp, compproto;
+ struct compreq *pcomp;
+ struct in_addr ipaddr, dstipaddr;
+ char tbuff[100];
+
+ plen = plength(bp);
+
+ cp = MBUF_CTOP(bp);
+ ackp = AckBuff;
+ nakp = NakBuff;
+ rejp = RejBuff;
+
+ while (plen >= sizeof(struct fsmconfig)) {
+ if (plen < 0)
+ break;
+ type = *cp;
+ length = cp[1];
+ if (type <= TY_BSD)
+ sprintf(tbuff, " %s[%d] ", cftypes[type], length);
+ else
+ sprintf(tbuff, " ");
+
+ LogPrintf(LOG_LCP, "%s\n", tbuff);
+
+ switch (type) {
+ case TY_PRED1:
+ switch (mode) {
+ case MODE_REQ:
+ if (Acceptable(ConfPred1)) {
+ bcopy(cp, ackp, length);
+ ackp += length;
+ CcpInfo.his_proto = type;
+ } else {
+ bcopy(cp, rejp, length);
+ rejp += length;
+ }
+ break;
+ case MODE_NAK:
+ case MODE_REJ:
+ CcpInfo.his_reject |= (1 << type);
+ CcpInfo.want_proto = 0;
+ break;
+ }
+ break;
+ case TY_BSD:
+ default:
+ CcpInfo.my_reject |= (1 << type);
+ bcopy(cp, rejp, length);
+ rejp += length;
+ break;
+ }
+ plen -= length;
+ cp += length;
+ }
+}
+
+void
+CcpInput(struct mbuf *bp)
+{
+ if (phase == PHASE_NETWORK)
+ FsmInput(&CcpFsm, bp);
+ else {
+ logprintf("ccp in phase %d\n", phase);
+ pfree(bp);
+ }
+}
diff --git a/usr.sbin/ppp/ccp.h b/usr.sbin/ppp/ccp.h
new file mode 100644
index 0000000..a544430
--- /dev/null
+++ b/usr.sbin/ppp/ccp.h
@@ -0,0 +1,52 @@
+/*
+ * 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. 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:
+ */
+
+#ifndef _CCP_H_
+#define _CCP_H_
+
+#define CCP_MAXCODE CODE_RESETACK
+
+#define TY_OUI 0 /* OUI */
+#define TY_PRED1 1 /* Predictor type 1 */
+#define TY_PRED2 2 /* Predictor type 2 */
+#define TY_PUDDLE 3 /* Puddle Jumper */
+#define TY_HWPPC 16 /* Hewlett-Packard PPC */
+#define TY_STAC 17 /* Stac Electronics LZS */
+#define TY_MSPPC 18 /* Microsoft PPC */
+#define TY_GAND 19 /* Gandalf FZA */
+#define TY_V42BIS 20 /* V.42bis compression */
+#define TY_BSD 21 /* BSD LZW Compress */
+
+struct ccpstate {
+ u_long his_proto; /* peer's compression protocol */
+ u_long want_proto; /* my compression protocol */
+
+ u_long his_reject; /* Request codes rejected by peer */
+ u_long my_reject; /* Request codes I have rejected */
+
+ u_long orgout, compout;
+ u_long orgin, compin;
+};
+
+extern struct ccpstate CcpInfo;
+
+#endif
diff --git a/usr.sbin/ppp/chap.c b/usr.sbin/ppp/chap.c
new file mode 100644
index 0000000..2b86b40
--- /dev/null
+++ b/usr.sbin/ppp/chap.c
@@ -0,0 +1,259 @@
+/*
+ * PPP CHAP 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 Imprement retransmission timer.
+ */
+#include "fsm.h"
+#include "chap.h"
+#include "lcpproto.h"
+#include "lcp.h"
+#include "hdlc.h"
+#include "phase.h"
+#include "vars.h"
+
+static int chapid;
+
+static char *chapcodes[] = {
+ "???", "CHALLENGE", "RESPONCE", "SUCCESS", "FAILURE"
+};
+
+extern char *AuthGetSecret();
+
+void
+ChapOutput(code, id, ptr, count)
+u_int code, id;
+u_char *ptr;
+int count;
+{
+ int plen;
+ struct fsmheader lh;
+ struct mbuf *bp;
+
+ plen = sizeof(struct fsmheader) + count;
+ lh.code = code;
+ lh.id = id;
+ lh.length = htons(plen);
+ bp = mballoc(plen, MB_FSM);
+ bcopy(&lh, MBUF_CTOP(bp), sizeof(struct fsmheader));
+ if (count)
+ bcopy(ptr, MBUF_CTOP(bp) + sizeof(struct fsmheader), count);
+#ifdef DEBUG
+ DumpBp(bp);
+#endif
+ LogPrintf(LOG_LCP, "ChapOutput: %s\n", chapcodes[code]);
+ HdlcOutput(PRI_NORMAL, PROTO_CHAP, bp);
+}
+
+
+static char challenge_data[80];
+static int challenge_len;
+
+void
+SendChapChallenge()
+{
+ int keylen, len, i;
+ char *cp;
+
+ srandom(time(NULL));
+ ++chapid;
+
+ cp = challenge_data;
+ *cp++ = challenge_len = random() % 32 + 16;
+ for (i = 0; i < challenge_len; i++)
+ *cp++ = random() & 0xff;
+ len = strlen(VarAuthName);
+ bcopy(VarAuthName, cp, len);
+ cp += len;
+ ChapOutput(CHAP_CHALLENGE, chapid, challenge_data, cp - challenge_data);
+}
+
+#ifdef DEBUG
+void
+DumpDigest(mes, cp, len)
+char *mes;
+char *cp;
+{
+ int i;
+
+ logprintf("%s: ", mes);
+ for (i = 0; i < len; i++) {
+ logprintf(" %02x", *cp++ & 0xff);
+ }
+ logprintf("\n");
+}
+#endif
+
+void
+RecvChapTalk(chp, bp)
+struct fsmheader *chp;
+struct mbuf *bp;
+{
+ int valsize, len;
+ int arglen, keylen, namelen;
+ char *cp, *argp, *ap, *name, *digest;
+ char *keyp;
+ MD5_CTX context; /* context */
+ char answer[100];
+ char cdigest[16];
+
+ len = ntohs(chp->length);
+#ifdef DEBUG
+ logprintf("length: %d\n", len);
+#endif
+ arglen = len - sizeof(struct fsmheader);
+ cp = (char *)MBUF_CTOP(bp);
+ valsize = *cp++ & 255;
+ name = cp + valsize;
+ namelen = arglen - valsize - 1;
+ name[namelen] = 0;
+ LogPrintf(LOG_PHASE, " Valsize = %d, Name = %s\n", valsize, name);
+
+ /*
+ * Get a secret key corresponds to the peer
+ */
+ keyp = AuthGetSecret(SECRETFILE, name, namelen, chp->code == CHAP_RESPONSE);
+
+ switch (chp->code) {
+ case CHAP_CHALLENGE:
+ if (keyp) {
+ keylen = strlen(keyp);
+ } else {
+ keylen = strlen(VarAuthKey);
+ keyp = VarAuthKey;
+ }
+ name = VarAuthName;
+ namelen = strlen(VarAuthName);
+ argp = malloc(1 + valsize + namelen);
+ digest = argp;
+ *digest++ = 16; /* value size */
+ ap = answer;
+ *ap++ = chp->id;
+ bcopy(keyp, ap, keylen);
+ ap += keylen;
+ bcopy(cp, ap, valsize);
+#ifdef DEBUG
+ DumpDigest("recv", ap, valsize);
+#endif
+ ap += valsize;
+ MD5Init(&context);
+ MD5Update(&context, answer, ap - answer);
+ MD5Final(digest, &context);
+#ifdef DEBUG
+ DumpDigest("answer", digest, 16);
+#endif
+ bcopy(name, digest + 16, namelen);
+ ap += namelen;
+ /* Send answer to the peer */
+ ChapOutput(CHAP_RESPONSE, chp->id, argp, namelen + 17);
+ break;
+ case CHAP_RESPONSE:
+ if (keyp) {
+ /*
+ * Compute correct digest value
+ */
+ keylen = strlen(keyp);
+ ap = answer;
+ *ap++ = chp->id;
+ bcopy(keyp, ap, keylen);
+ ap += keylen;
+ MD5Init(&context);
+ MD5Update(&context, answer, ap - answer);
+ MD5Update(&context, challenge_data+1, challenge_len);
+ MD5Final(cdigest, &context);
+#ifdef DEBUG
+ DumpDigest("got", cp, 16);
+ DumpDigest("expect", cdigest, 16);
+#endif
+ /*
+ * Compare with the response
+ */
+ if (bcmp(cp, cdigest, 16) == 0) {
+ ChapOutput(CHAP_SUCCESS, chp->id, "Wellcome!!", 10);
+ NewPhase(PHASE_NETWORK);
+ break;
+ }
+ }
+ /*
+ * Peer is not registerd, or response digest is wrong.
+ */
+ ChapOutput(CHAP_FAILURE, chp->id, "Invalid!!", 9);
+ LcpClose();
+ break;
+ }
+}
+
+void
+RecvChapResult(chp, bp)
+struct fsmheader *chp;
+struct mbuf *bp;
+{
+ int len;
+ struct lcpstate *lcp = &LcpInfo;
+
+ len = ntohs(chp->length);
+#ifdef DEBUG
+ logprintf("length: %d\n", len);
+#endif
+ if (chp->code == CHAP_SUCCESS) {
+ if (lcp->auth_iwait == PROTO_CHAP) {
+ lcp->auth_iwait = 0;
+ if (lcp->auth_ineed == 0)
+ NewPhase(PHASE_NETWORK);
+ }
+ } else {
+ /*
+ * Maybe, we shoud close LCP. Of cause, peer may take close action, too.
+ */
+ ;
+ }
+}
+
+void
+ChapInput(struct mbuf *bp)
+{
+ int len = plength(bp);
+ struct fsmheader *chp;
+
+ if (len >= sizeof(struct fsmheader)) {
+ chp = (struct fsmheader *)MBUF_CTOP(bp);
+ if (len >= ntohs(chp->length)) {
+ if (chp->code < 1 || chp->code > 4)
+ chp->code = 0;
+ LogPrintf(LOG_LCP, "ChapInput: %s\n", chapcodes[chp->code]);
+
+ bp->offset += sizeof(struct fsmheader);
+ bp->cnt -= sizeof(struct fsmheader);
+
+ switch (chp->code) {
+ case CHAP_CHALLENGE:
+ case CHAP_RESPONSE:
+ RecvChapTalk(chp, bp);
+ break;
+ case CHAP_SUCCESS:
+ case CHAP_FAILURE:
+ RecvChapResult(chp, bp);
+ break;
+ }
+ }
+ }
+ pfree(bp);
+}
diff --git a/usr.sbin/ppp/chap.h b/usr.sbin/ppp/chap.h
new file mode 100644
index 0000000..edb09b3
--- /dev/null
+++ b/usr.sbin/ppp/chap.h
@@ -0,0 +1,32 @@
+/*
+ * 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. 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:
+ */
+
+#ifndef _CHAP_H_
+#define _CHAP_H_
+#include "global.h"
+#include "md5.h"
+
+#define CHAP_CHALLENGE 1
+#define CHAP_RESPONSE 2
+#define CHAP_SUCCESS 3
+#define CHAP_FAILURE 4
+#endif
diff --git a/usr.sbin/ppp/chat.c b/usr.sbin/ppp/chat.c
new file mode 100644
index 0000000..ad1378e
--- /dev/null
+++ b/usr.sbin/ppp/chat.c
@@ -0,0 +1,377 @@
+/*
+ * Written by Toshiharu OHNO (tony-o@iij.ad.jp)
+ *
+ * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
+ *
+ * Most of codes are derived from chat.c by Karl Fox (karl@MorningStar.Com).
+ *
+ * Chat -- a program for automatic session establishment (i.e. dial
+ * the phone and log in).
+ *
+ * This software is in the public domain.
+ *
+ * Please send all bug reports, requests for information, etc. to:
+ *
+ * Karl Fox <karl@MorningStar.Com>
+ * Morning Star Technologies, Inc.
+ * 1760 Zollinger Road
+ * Columbus, OH 43221
+ * (614)451-1883
+ *
+ * $Id:$
+ *
+ * TODO:
+ * o Support more UUCP compatible control sequences.
+ * o Dialing shoud not block monitor process.
+ */
+#include "defs.h"
+#include <ctype.h>
+#include <sys/uio.h>
+#ifndef isblank
+#define isblank(c) ((c) == '\t' || (c) == ' ')
+#endif
+#include <sys/time.h>
+#include <fcntl.h>
+#include "timeout.h"
+#include "vars.h"
+
+static int TimeoutSec;
+static int abort_next, timeout_next;
+static int numaborts;
+char *AbortStrings[50];
+
+extern int ChangeParity(char *);
+
+#define MATCH 1
+#define NOMATCH 0
+#define ABORT -1
+
+static char *
+findblank(p, instring)
+char *p;
+int instring;
+{
+ if (instring) {
+ while (*p) {
+ if (*p == '\\') {
+ strcpy(p, p + 1);
+ if (!*p)
+ break;
+ } else if (*p == '"')
+ return(p);
+ p++;
+ }
+ } else {
+ while (*p) {
+ if (isblank(*p))
+ return(p);
+ p++;
+ }
+ }
+ return p;
+}
+
+int
+MakeArgs(script, pvect)
+char *script;
+char **pvect;
+{
+ int nargs, nb;
+ int instring;
+
+ nargs = 0;
+ while (*script) {
+ nb = strspn(script, " \t");
+ script += nb;
+ if (*script) {
+ if (*script == '"') {
+ instring = 1;
+ script++;
+ if (*script == '\0')
+ return(nargs);
+ } else
+ instring = 0;
+ *pvect++ = script;
+ nargs++;
+ script = findblank(script, instring);
+ if (*script)
+ *script++ = '\0';
+ }
+ }
+ *pvect = NULL;
+ return nargs;
+}
+
+/*
+ * \r Carrige return character
+ * \s Space character
+ * \n Line feed character
+ * \T Telephone number (defined via `set phone'
+ * \t Tab character
+ */
+char *
+ExpandString(str, result, sendmode)
+char *str;
+char *result;
+int sendmode;
+{
+ int addcr = 0;
+
+ if (sendmode)
+ addcr = 1;
+ while (*str) {
+ switch (*str) {
+ case '\\':
+ str++;
+ switch (*str) {
+ case 'c':
+ if (sendmode)
+ addcr = 0;
+ break;
+ case 'd': /* Delay 2 seconds */
+ sleep(2); break;
+ case 'p':
+ usleep(250000); break; /* Pause 0.25 sec */
+ case 'n':
+ *result++ = '\n'; break;
+ case 'r':
+ *result++ = '\r'; break;
+ case 's':
+ *result++ = ' '; break;
+ case 't':
+ *result++ = '\t'; break;
+ case 'P':
+ bcopy(VarAuthKey, result, strlen(VarAuthKey));
+ result += strlen(VarAuthKey);
+ break;
+ case 'T':
+ bcopy(VarPhone, result, strlen(VarPhone));
+ result += strlen(VarPhone);
+ break;
+ case 'U':
+ bcopy(VarAuthName, result, strlen(VarAuthName));
+ result += strlen(VarAuthName);
+ break;
+ default:
+ *result++ = *str; break;
+ }
+ if (*str) str++;
+ break;
+ case '^':
+ str++;
+ if (*str)
+ *result++ = *str++ & 0x1f;
+ break;
+ default:
+ *result++ = *str++;
+ break;
+ }
+ }
+ if (addcr)
+ *result++ = '\r';
+ *result++ = '\0';
+ return(result);
+}
+
+int
+WaitforString(estr)
+char *estr;
+{
+#define IBSIZE 200
+ struct timeval timeout;
+ char *s, *str, ch;
+ char *inp;
+ fd_set rfds;
+ int i, nfds;
+ char buff[200];
+ char inbuff[IBSIZE];
+
+ (void) ExpandString(estr, buff, 0);
+ LogPrintf(LOG_CHAT, "Wait for (%d): %s --> %s\n", TimeoutSec, estr, buff);
+ str = buff;
+ inp = inbuff;
+
+ nfds = modem + 1;
+ s = str;
+ for (;;) {
+ FD_ZERO(&rfds);
+ FD_SET(modem, &rfds);
+ /*
+ * Because it is not clear whether select() modifies timeout value,
+ * it is better to initialize timeout values everytime.
+ */
+ timeout.tv_sec = TimeoutSec;
+ timeout.tv_usec = 0;
+
+ i = select(nfds, &rfds, NULL, NULL, &timeout);
+#ifdef notdef
+ TimerService();
+#endif
+ if (i < 0) {
+ perror("select");
+ return(NOMATCH);
+ } else if (i == 0) { /* Timeout reached! */
+ LogPrintf(LOG_CHAT, "can't get (%d).\n", timeout.tv_sec);
+ return(NOMATCH);
+ }
+ if (FD_ISSET(modem, &rfds)) { /* got something */
+ read(modem, &ch, 1);
+ *inp++ = ch;
+ if (ch == *s) {
+ s++;
+ if (*s == '\0') {
+ return(MATCH);
+ }
+ } else {
+ s = str;
+ if (inp == inbuff+ IBSIZE) {
+ bcopy(inp - 100, inbuff, 100);
+ inp = inbuff + 100;
+ }
+ for (i = 0; i < numaborts; i++) { /* Look for Abort strings */
+ int len;
+ char *s1;
+
+ s1 = AbortStrings[i];
+ len = strlen(s1);
+ if ((len <= inp - inbuff) && (strncmp(inp - len, s1, len) == 0)) {
+ LogPrintf(LOG_CHAT, "Abort: %s\n", s1);
+ return(ABORT);
+ }
+ }
+ }
+ }
+ }
+}
+
+void
+SendString(str)
+char *str;
+{
+ char buff[200];
+
+ if (abort_next) {
+ abort_next = 0;
+ ExpandString(str, buff, 0);
+ AbortStrings[numaborts++] = strdup(buff);
+ } else if (timeout_next) {
+ timeout_next = 0;
+ TimeoutSec = atoi(str);
+ if (TimeoutSec <= 0)
+ TimeoutSec = 30;
+ } else {
+ (void) ExpandString(str, buff, 1);
+ LogPrintf(LOG_CHAT, "sending: %s\n", buff);
+ write(modem, buff, strlen(buff));
+ }
+}
+
+int
+ExpectString(str)
+char *str;
+{
+ char *minus;
+ int state;
+
+ if (strcmp(str, "ABORT") == 0) {
+ ++abort_next;
+ return(MATCH);
+ }
+ if (strcmp(str, "TIMEOUT") == 0) {
+ ++timeout_next;
+ return(MATCH);
+ }
+ LogPrintf(LOG_CHAT, "Expecting %s\n", str);
+ while (*str) {
+ /*
+ * Check whether if string contains sub-send-expect.
+ */
+ for (minus = str; *minus; minus++) {
+ if (*minus == '-') {
+ if (minus == str || minus[-1] != '\\')
+ break;
+ }
+ }
+ if (*minus == '-') { /* We have sub-send-expect. */
+ *minus++ = '\0';
+ state = WaitforString(str);
+ if (state != NOMATCH)
+ return(state);
+ /*
+ * Can't get expect string. Sendout send part.
+ */
+ str = minus;
+ for (minus = str; *minus; minus++) {
+ if (*minus == '-') {
+ if (minus == str || minus[-1] != '\\')
+ break;
+ }
+ }
+ if (*minus == '-') {
+ *minus++ = '\0';
+ SendString(str);
+ str = minus;
+ } else {
+ SendString(str);
+ return(MATCH);
+ }
+ } else {
+ /*
+ * Simple case. Wait for string.
+ */
+ return(WaitforString(str));
+ }
+ }
+ return(MATCH);
+}
+
+int
+DoChat(script)
+char *script;
+{
+ char *vector[20];
+ char **argv;
+ int argc, n, state;
+#ifdef DEBUG
+ int i;
+#endif
+
+ timeout_next = abort_next = 0;
+ for (n = 0; AbortStrings[n]; n++) {
+ free(AbortStrings[n]);
+ AbortStrings[n] = NULL;
+ }
+ numaborts = 0;
+
+ bzero(vector, sizeof(vector));
+ n = MakeArgs(script, &vector);
+#ifdef DEBUG
+ logprintf("n = %d\n", n);
+ for (i = 0; i < n; i++)
+ logprintf(" %s\n", vector[i]);
+#endif
+ argc = n;
+ argv = vector;
+ TimeoutSec = 30;
+ while (*argv) {
+ if (strcmp(*argv, "P_ZERO") == 0 ||
+ strcmp(*argv, "P_ODD") == 0 || strcmp(*argv, "P_EVEN") == 0) {
+ ChangeParity(*argv++);
+ continue;
+ }
+ state = ExpectString(*argv++);
+ switch (state) {
+ case MATCH:
+ if (*argv)
+ SendString(*argv++);
+ break;
+ case ABORT:
+#ifdef notdef
+ HangupModem();
+#endif
+ case NOMATCH:
+ return(NOMATCH);
+ }
+ }
+ return(MATCH);
+}
diff --git a/usr.sbin/ppp/command.c b/usr.sbin/ppp/command.c
new file mode 100644
index 0000000..8c0d203
--- /dev/null
+++ b/usr.sbin/ppp/command.c
@@ -0,0 +1,807 @@
+/*
+ * PPP User command processing 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:$
+ *
+ */
+#include <ctype.h>
+#include "fsm.h"
+#include "phase.h"
+#include "lcp.h"
+#include "ipcp.h"
+#include "modem.h"
+#include "command.h"
+#include "hdlc.h"
+#include "vars.h"
+#include <netdb.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <net/route.h>
+#include "os.h"
+
+extern int MakeArgs();
+extern void Cleanup(), TtyTermMode(), PacketMode();
+extern int EnableCommand(), DisableCommand(), DisplayCommand();
+extern int AcceptCommand(), DenyCommand();
+extern int LoadCommand(), SaveCommand();
+extern int ChangeParity(char *);
+extern int SelectSystem();
+extern int ShowRoute();
+
+struct in_addr ifnetmask;
+
+static int ShowCommand(), TerminalCommand(), QuitCommand();
+static int CloseCommand(), DialCommand(), DownCommand();
+static int SetCommand(), AddCommand(), DeleteCommand();
+
+static int
+HelpCommand(list, argc, argv, plist)
+struct cmdtab *list;
+int argc;
+char **argv;
+struct cmdtab *plist;
+{
+ struct cmdtab *cmd;
+ int n;
+ char c;
+
+ if (argc > 0) {
+ for (cmd = plist; cmd->name; cmd++) {
+ if (strcmp(cmd->name, *argv) == 0) {
+ printf("%s %s\n", cmd->name, cmd->syntax);
+ return(1);
+ }
+ }
+ return(1);
+ }
+ n = 0;
+ for (cmd = plist; cmd->func; cmd++) {
+ c = (n & 1)? '\n' : '\t';
+ if (cmd->name) {
+ printf(" %-8s: %-20s%c", cmd->name, cmd->helpmes, c);
+ n++;
+ }
+ }
+ if (n & 1)
+ printf("\n");
+ return(1);
+}
+
+int
+IsInteractive()
+{
+ char *mes = NULL;
+
+ if (mode & MODE_AUTO)
+ mes = "Working as auto mode.";
+ else if (mode & MODE_DIRECT)
+ mes = "Working as direct mode.";
+ else if (mode & MODE_DEDICATED)
+ mes = "Workring as dedicated mode.";
+ if (mes) {
+ printf("%s\n", mes);
+ return(0);
+ }
+ return(1);
+}
+
+static int
+DialCommand(cmdlist, argc, argv)
+struct cmdtab *cmdlist;
+int argc;
+char **argv;
+{
+ if (LcpFsm.state > ST_CLOSED) {
+ printf("LCP state is [%s]\n", StateNames[LcpFsm.state]);
+ return(1);
+ }
+ if (!IsInteractive())
+ return(1);
+ modem = OpenModem(mode);
+ if (modem < 0) {
+ printf("failed to open modem.\n");
+ modem = 0;
+ return(1);
+ }
+ if (argc > 0) {
+ if (SelectSystem(*argv, CONFFILE) < 0) {
+ printf("%s: not found.\n", *argv);
+ return(1);
+ }
+ }
+ if (DialModem()) {
+ sleep(1);
+ ModemTimeout();
+ PacketMode();
+ }
+ return(1);
+}
+
+static char StrOption[] = "option ..";
+static char StrRemote[] = "[remote]";
+char StrNull[] = "";
+
+struct cmdtab Commands[] = {
+ { "accept", NULL, AcceptCommand,
+ "accept option request", StrOption },
+ { "add", NULL, AddCommand,
+ "add route", "dest mask gateway" },
+ { "close", NULL, CloseCommand,
+ "Close connection", StrNull },
+ { "delete", NULL, DeleteCommand,
+ "delete route", "dest gateway" },
+ { "deny", NULL, DenyCommand,
+ "Deny option request", StrOption },
+ { "dial", "call", DialCommand,
+ "Dial and login", StrRemote },
+ { "disable", NULL, DisableCommand,
+ "Disable option", StrOption },
+ { "display", NULL, DisplayCommand,
+ "Display option configs", StrNull },
+ { "enable", NULL, EnableCommand,
+ "Enable option", StrOption },
+ { "load", NULL, LoadCommand,
+ "Load settings", StrRemote },
+ { "save", NULL, SaveCommand,
+ "Save settings", StrNull },
+ { "set", "setup", SetCommand,
+ "Set parameters", "var value" },
+ { "show", NULL, ShowCommand,
+ "Show status and statictics", "var" },
+ { "term", NULL, TerminalCommand,
+ "Enter to terminal mode", StrNull },
+ { "quit", "bye", QuitCommand,
+ "Quit PPP program", StrNull },
+ { "help", "?", HelpCommand,
+ "Display this message", "[command]", (void *)Commands },
+ { NULL, "down", DownCommand,
+ "Generate down event", StrNull },
+ { NULL, NULL, NULL },
+};
+
+extern int ReportCcpStatus();
+extern int ReportLcpStatus();
+extern int ReportIpcpStatus();
+extern int ReportProtStatus();
+extern int ReportCompress();
+extern int ShowModemStatus();
+extern int ReportHdlcStatus();
+extern int ShowMemMap();
+
+static char *LogLevelName[] = {
+ LM_PHASE, LM_CHAT, LM_LQM, LM_LCP,
+ LM_TCPIP, LM_HDLC, LM_ASYNC,
+};
+
+static int ShowDebugLevel()
+{
+ int i;
+
+ printf("%02x: ", loglevel);
+ for (i = LOG_PHASE; i < MAXLOGLEVEL; i++) {
+ if (loglevel & (1 << i))
+ printf("%s ", LogLevelName[i]);
+ }
+ printf("\n");
+ return(1);
+}
+
+static int ShowEscape()
+{
+ int code, bit;
+
+ if (EscMap[32]) {
+ for (code = 0; code < 32; code++) {
+ if (EscMap[code]) {
+ for (bit = 0; bit < 8; bit++) {
+ if (EscMap[code] & (1<<bit)) {
+ printf(" 0x%02x", (code << 3) + bit);
+ }
+ }
+ }
+ }
+ printf("\n");
+ }
+ return(1);
+}
+
+static int ShowTimeout()
+{
+ printf(" Idle Timer: %d secs LQR Timer: %d secs\n",
+ VarIdleTimeout, VarLqrTimeout);
+ return(1);
+}
+
+static int ShowAuthKey()
+{
+ printf("AuthName = %s\n", VarAuthName);
+ printf("AuthKey = %s\n", VarAuthKey);
+ return(1);
+}
+
+static int ShowVersion()
+{
+ extern char *VarVersion[];
+
+ printf("%s\n", VarVersion);
+ return(1);
+}
+
+static int ShowLogList()
+{
+ ListLog();
+ return(1);
+}
+
+extern int ShowIfilter(), ShowOfilter(), ShowDfilter();
+
+struct cmdtab ShowCommands[] = {
+ { "auth", NULL, ShowAuthKey, "Show auth name/key",
+ StrNull, },
+ { "ccp", NULL, ReportCcpStatus, "Show CCP status",
+ StrNull, },
+ { "compress", NULL, ReportCompress, "Show compression statictics",
+ StrNull },
+ { "debug", NULL, ShowDebugLevel, "Show current debug level",
+ StrNull },
+ { "dfilter", NULL, ShowDfilter, "Show Demand filters",
+ StrOption },
+ { "escape", NULL, ShowEscape, "Show escape characters",
+ StrNull },
+ { "hdlc", NULL, ReportHdlcStatus, "Show HDLC error summary",
+ StrNull },
+ { "ifilter", NULL, ShowIfilter, "Show Input filters",
+ StrOption },
+ { "ipcp", NULL, ReportIpcpStatus, "Show IPCP status",
+ StrNull, },
+ { "lcp", NULL, ReportLcpStatus, "Show LCP status",
+ StrNull, },
+ { "log", NULL, ShowLogList, "Show log records",
+ StrNull, },
+ { "mem", NULL, ShowMemMap, "Show memory map",
+ StrNull, },
+ { "modem", NULL, ShowModemStatus, "Show modem setups",
+ StrNull, },
+ { "ofilter", NULL, ShowOfilter, "Show Output filters",
+ StrOption },
+ { "proto", NULL, ReportProtStatus, "Show protocol summary",
+ StrNull, },
+ { "route", NULL, ShowRoute, "Show routing table",
+ StrNull, },
+ { "timeout", NULL, ShowTimeout, "Show Idle timeout value",
+ StrNull, },
+ { "version", NULL, ShowVersion, "Show version string",
+ StrNull, },
+ { "help", "?", HelpCommand, "Display this message",
+ StrNull, (void *)ShowCommands },
+ { NULL, NULL, NULL },
+};
+
+struct cmdtab *
+FindCommand(cmds, str, pmatch)
+struct cmdtab *cmds;
+char *str;
+int *pmatch;
+{
+ int nmatch = 0;
+ int len = strlen(str);
+ struct cmdtab *found = NULL;
+
+ while (cmds->func) {
+ if (cmds->name && strncmp(str, cmds->name, len) == 0) {
+ nmatch++;
+ found = cmds;
+ } else if (cmds->alias && strncmp(str, cmds->alias, len) == 0) {
+ nmatch++;
+ found = cmds;
+ }
+ cmds++;
+ }
+ *pmatch = nmatch;
+ return(found);
+}
+
+int
+FindExec(cmdlist, argc, argv)
+struct cmdtab *cmdlist;
+int argc;
+char **argv;
+{
+ struct cmdtab *cmd;
+ int val = 1;
+ int nmatch;
+
+ cmd = FindCommand(cmdlist, *argv, &nmatch);
+ if (nmatch > 1)
+ printf("Anbiguous.\n");
+ else if (cmd)
+ val = (cmd->func)(cmd, --argc, ++argv, cmd->args);
+ else
+ printf("what?\n");
+ return(val);
+}
+
+void
+Prompt(flag)
+int flag;
+{
+ if (!(mode & MODE_INTER))
+ return;
+ if (flag) printf("\n");
+ if (IpcpFsm.state == ST_OPENED && phase == PHASE_NETWORK)
+ printf("PPP> ");
+ else
+ printf("ppp> ");
+ fflush(stdout);
+}
+
+void
+DecodeCommand(buff, nb, prompt)
+char *buff;
+int nb;
+int prompt;
+{
+ char *vector[20];
+ char **argv;
+ int argc, val;
+ char *cp;
+
+ val = 1;
+ if (nb > 0) {
+ cp = buff + strcspn(buff, "\r\n");
+ if (cp)
+ *cp = '\0';
+ {
+ argc = MakeArgs(buff, &vector);
+ argv = vector;
+
+ if (argc > 0)
+ val = FindExec(Commands, argc, argv);
+ }
+ }
+ if (val && prompt)
+ Prompt(0);
+}
+
+static int
+ShowCommand(list, argc, argv)
+struct cmdtab *list;
+int argc;
+char **argv;
+{
+ int val = 1;
+
+ if (argc > 0)
+ val = FindExec(ShowCommands, argc, argv);
+ else
+ printf("Use ``show ?'' to get a list.\n");
+ return(val);
+}
+
+static int
+TerminalCommand()
+{
+ if (LcpFsm.state > ST_CLOSED) {
+ printf("LCP state is [%s]\n", StateNames[LcpFsm.state]);
+ return(1);
+ }
+ if (!IsInteractive())
+ return(1);
+ modem = OpenModem(mode);
+ if (modem < 0) {
+ printf("failed to open modem.\n");
+ modem = 0;
+ return(1);
+ }
+ printf("Enter to terminal mode.\n");
+ printf("Type `~?' for help.\n");
+ TtyTermMode();
+ return(0);
+}
+
+static int
+QuitCommand(list, argc, argv)
+struct cmdtab *list;
+int argc;
+char **argv;
+{
+ if (mode & (MODE_DIRECT|MODE_DEDICATED|MODE_AUTO)) {
+ if (argc > 0) {
+ Cleanup(EX_NORMAL);
+ } else {
+ close(netfd);
+ close(1);
+ netfd = -1;
+ mode &= ~MODE_INTER;
+ }
+ } else
+ Cleanup(EX_NORMAL);
+ return(1);
+}
+
+static int
+CloseCommand()
+{
+ LcpClose();
+ return(1);
+}
+
+static int
+DownCommand()
+{
+ LcpDown();
+ return(1);
+}
+
+static int validspeed[] = {
+ 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 0
+};
+
+static int SetModemSpeed(list, argc, argv)
+struct cmdtab *list;
+int argc;
+char **argv;
+{
+ int speed;
+ int *sp;
+
+ if (argc > 0) {
+ speed = atoi(*argv);
+ for (sp = validspeed; *sp; sp++) {
+ if (*sp == speed) {
+ VarSpeed = speed;
+ return(1);
+ }
+ }
+ printf("invalid speed.\n");
+ }
+ return(1);
+}
+
+static int SetModemParity(list, argc, argv)
+struct cmdtab *list;
+int argc;
+char **argv;
+{
+ int parity;
+
+ if (argc > 0) {
+ parity = ChangeParity(*argv);
+ if (parity < 0)
+ printf("Invalid parity.\n");
+ else
+ VarParity = parity;
+ }
+ return(1);
+}
+
+static int
+SetDebugLevel(list, argc, argv)
+struct cmdtab *list;
+int argc;
+char **argv;
+{
+ int level, w;
+
+ for (level = 0; argc-- > 0; argv++) {
+ if (isdigit(**argv)) {
+ w = atoi(*argv);
+ if (w < 0 || w >= MAXLOGLEVEL) {
+ printf("invalid log level.\n");
+ break;
+ } else
+ level |= (1 << w);
+ } else {
+ for (w = 0; w < MAXLOGLEVEL; w++) {
+ if (strcasecmp(*argv, LogLevelName[w]) == 0) {
+ level |= (1 << w);
+ continue;
+ }
+ }
+ }
+ }
+ loglevel = level;
+ return(1);
+}
+
+static int
+SetEscape(list, argc, argv)
+struct cmdtab *list;
+int argc;
+char **argv;
+{
+ int code;
+
+ for (code = 0; code < 33; code++)
+ EscMap[code] = 0;
+ while (argc-- > 0) {
+ sscanf(*argv++, "%x", &code);
+ code &= 0xff;
+ EscMap[code >> 3] |= (1 << (code&7));
+ EscMap[32] = 1;
+ }
+ return(1);
+}
+
+static int
+SetInitialMRU(list, argc, argv)
+struct cmdtab *list;
+int argc;
+char **argv;
+{
+ int mru;
+
+ if (argc > 0) {
+ mru = atoi(*argv);
+ if (mru < 100)
+ printf("given value is too small.\n");
+ else if (mru > MAX_MRU)
+ printf("given value is too big.\n");
+ else
+ VarMRU = mru;
+ }
+ return(1);
+}
+
+static int
+SetIdleTimeout(list, argc, argv)
+struct cmdtab *list;
+int argc;
+char **argv;
+{
+ if (argc-- > 0) {
+ VarIdleTimeout = atoi(*argv++);
+ if (argc > 0)
+ VarLqrTimeout = atoi(*argv);
+ }
+ return(1);
+}
+
+struct in_addr
+GetIpAddr(cp)
+char *cp;
+{
+ struct hostent *hp;
+ struct in_addr ipaddr;
+
+ hp = gethostbyname(cp);
+ if (hp && hp->h_addrtype == AF_INET)
+ bcopy(hp->h_addr, &ipaddr, hp->h_length);
+ else if (inet_aton(cp, &ipaddr) == 0)
+ ipaddr.s_addr = 0;
+ return(ipaddr);
+}
+
+static int
+SetInterfaceAddr(list, argc, argv)
+struct cmdtab *list;
+int argc;
+char **argv;
+{
+ int width;
+
+ DefMyAddress.ipaddr.s_addr = DefHisAddress.ipaddr.s_addr = 0L;
+ if (argc > 0) {
+ ParseAddr(argc, argv++,
+ &DefMyAddress.ipaddr, &DefMyAddress.mask, &DefMyAddress.width);
+ if (--argc > 0) {
+ ParseAddr(argc, argv++,
+ &DefHisAddress.ipaddr, &DefHisAddress.mask, &DefHisAddress.width);
+ if (--argc > 0) {
+ ifnetmask = GetIpAddr(*argv);
+ }
+ }
+ }
+ /*
+ * For backwards compatibility, 0.0.0.0 means any address.
+ */
+ if (DefMyAddress.ipaddr.s_addr == 0) {
+ DefMyAddress.mask.s_addr = 0;
+ DefMyAddress.width = 0;
+ }
+ if (DefHisAddress.ipaddr.s_addr == 0) {
+ DefHisAddress.mask.s_addr = 0;
+ DefHisAddress.width = 0;
+ }
+
+ if ((mode & MODE_AUTO) |
+ ((mode & MODE_DEDICATED) && dstsystem)) {
+ OsSetIpaddress(DefMyAddress.ipaddr, DefHisAddress.ipaddr, ifnetmask);
+ }
+ return(1);
+}
+
+
+#define VAR_AUTHKEY 0
+#define VAR_DIAL 1
+#define VAR_LOGIN 2
+#define VAR_AUTHNAME 3
+#define VAR_DEVICE 4
+#define VAR_ACCMAP 5
+#define VAR_PHONE 6
+
+static int
+SetVariable(list, argc, argv, param)
+struct cmdtab *list;
+int argc;
+char **argv;
+int param;
+{
+ u_long map;
+
+ if (argc > 0) {
+ switch (param) {
+ case VAR_AUTHKEY:
+ strncpy(VarAuthKey, *argv, sizeof(VarAuthKey)-1);
+ break;
+ case VAR_AUTHNAME:
+ strncpy(VarAuthName, *argv, sizeof(VarAuthName)-1);
+ break;
+ case VAR_DIAL:
+ strncpy(VarDialScript, *argv, sizeof(VarDialScript)-1);
+ break;
+ case VAR_LOGIN:
+ strncpy(VarLoginScript, *argv, sizeof(VarDialScript)-1);
+ break;
+ case VAR_DEVICE:
+ strncpy(VarDevice, *argv, sizeof(VarDevice)-1);
+ break;
+ case VAR_ACCMAP:
+ sscanf(*argv, "%x", &map);
+ VarAccmap = map;
+ break;
+ case VAR_PHONE:
+ strncpy(VarPhone, *argv, sizeof(VarPhone)-1);
+ break;
+ }
+ }
+ return(1);
+}
+
+static int SetOpenMode(list, argc, argv)
+struct cmdtab *list;
+int argc;
+char **argv;
+{
+ if (argc > 0) {
+ if (strcmp(*argv, "active") == 0)
+ VarOpenMode = OPEN_ACTIVE;
+ else if (strcmp(*argv, "passive") == 0)
+ VarOpenMode = OPEN_PASSIVE;
+ else
+ printf("Invalid mode.\n");
+ }
+ return(1);
+}
+
+static char StrChatStr[] = "chat-script";
+static char StrValue[] = "value";
+
+extern int SetIfilter(), SetOfilter(), SetDfilter();
+
+struct cmdtab SetCommands[] = {
+ { "accmap", NULL, SetVariable, "Set accmap value",
+ "hex-value", (void *)VAR_ACCMAP },
+ { "authkey", "key", SetVariable, "Set authentication key",
+ "key", (void *)VAR_AUTHKEY },
+ { "authname", NULL, SetVariable, "Set authentication name",
+ "name", (void *)VAR_AUTHNAME },
+ { "debug", NULL, SetDebugLevel, "Set debug level",
+ StrValue },
+ { "device", "line", SetVariable, "Set modem device name",
+ "device-name", (void *)VAR_DEVICE },
+ { "dfilter", NULL, SetDfilter, "Set demand filter",
+ "..." },
+ { "dial", NULL, SetVariable, "Set dialing script",
+ StrChatStr, (void *)VAR_DIAL },
+ { "escape", NULL, SetEscape, "Set escape characters",
+ "hex-digit ..."},
+ { "ifaddr", NULL, SetInterfaceAddr, "Set destination address",
+ "src-addr dst-addr netmask" },
+ { "ifilter", NULL, SetIfilter, "Set input filter",
+ "..." },
+ { "login", NULL, SetVariable, "Set login script",
+ StrChatStr, (void *)VAR_LOGIN },
+ { "mru", "mtu", SetInitialMRU, "Set Initial MRU value",
+ StrValue },
+ { "ofilter", NULL, SetOfilter, "Set output filter",
+ "..." },
+ { "openmode", NULL, SetOpenMode, "Set open mode",
+ "[active|passive]" },
+ { "parity", NULL, SetModemParity, "Set modem parity",
+ "[odd|even|none]" },
+ { "phone", NULL, SetVariable, "Set telephone number",
+ "phone-number", (void *)VAR_PHONE },
+ { "speed", NULL, SetModemSpeed, "Set modem speed",
+ "speed" },
+ { "timeout", NULL, SetIdleTimeout, "Set Idle timeout",
+ StrValue },
+ { "help", "?", HelpCommand, "Display this message",
+ StrNull, (void *)SetCommands },
+ { NULL, NULL, NULL },
+};
+
+static int
+SetCommand(list, argc, argv)
+struct cmdtab *list;
+int argc;
+char **argv;
+{
+ int val = 1;
+
+ if (argc > 0)
+ val = FindExec(SetCommands, argc, argv);
+ else
+ printf("Use ``set ?'' to get a list.\n");
+ return(val);
+}
+
+
+static int
+AddCommand(list, argc, argv)
+struct cmdtab *list;
+int argc;
+char **argv;
+{
+ struct in_addr dest, gateway, netmask;
+
+ if (argc == 3) {
+ dest = GetIpAddr(argv[0]);
+ netmask = GetIpAddr(argv[1]);
+ if (strcmp(argv[2], "HISADDR") == 0)
+ gateway = IpcpInfo.his_ipaddr;
+ else
+ gateway = GetIpAddr(argv[2]);
+ OsSetRoute(RTM_ADD, dest, gateway, netmask);
+ } else {
+ printf("Usage: %s %s\n", list->name, list->syntax);
+ }
+ return(1);
+}
+
+static int
+DeleteCommand(list, argc, argv)
+struct cmdtab *list;
+int argc;
+char **argv;
+{
+ struct in_addr dest, gateway, netmask;
+
+ if (argc >= 2) {
+ dest = GetIpAddr(argv[0]);
+ if (strcmp(argv[1], "HISADDR") == 0)
+ gateway = IpcpInfo.his_ipaddr;
+ else
+ gateway = GetIpAddr(argv[1]);
+ netmask.s_addr = 0;
+ if (argc == 3) {
+ if (inet_aton(argv[1], &netmask) == 0) {
+ printf("bad netmask value.\n");
+ return(1);
+ }
+ }
+ OsSetRoute(RTM_DELETE, dest, gateway, netmask);
+ } else if (argc == 1 && strcmp(argv[0], "ALL") == 0) {
+ DeleteIfRoutes(0);
+ } else {
+ printf("Usage: %s %s\n", list->name, list->syntax);
+ }
+ return(1);
+}
+
diff --git a/usr.sbin/ppp/command.h b/usr.sbin/ppp/command.h
new file mode 100644
index 0000000..50b59ec
--- /dev/null
+++ b/usr.sbin/ppp/command.h
@@ -0,0 +1,30 @@
+/*
+ * 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. 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:
+ */
+
+struct cmdtab {
+ char *name;
+ char *alias;
+ int (*func)();
+ char *helpmes;
+ char *syntax;
+ void *args;
+};
diff --git a/usr.sbin/ppp/defs.h b/usr.sbin/ppp/defs.h
new file mode 100644
index 0000000..c0ec0c1
--- /dev/null
+++ b/usr.sbin/ppp/defs.h
@@ -0,0 +1,77 @@
+/*
+ * 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. 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:
+ */
+
+#ifndef _DEFS_H_
+#define _DEFS_H_
+
+#include <machine/endian.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "mbuf.h"
+#include "log.h"
+
+/*
+ * Check follwiing definitions for your machine envirinment
+ */
+#define LOGFILE "/var/log/ppp.log" /* Name of log file */
+#define MODEM_DEV "/dev/cua01" /* name of tty device */
+#define MODEM_SPEED B38400 /* tty speed */
+#define SERVER_PORT 3000 /* Base server port no. */
+
+#define REDIAL_PERIOD 30 /* Hold time to redial */
+
+#define CONFFILE "ppp.conf"
+#define LINKFILE "ppp.linkup"
+#define ETHERFILE "ppp.etherup"
+#define SECRETFILE "ppp.secret"
+
+/*
+ * Definition of working mode
+ */
+#define MODE_INTER 1 /* Interactive mode */
+#define MODE_AUTO 2 /* Auto calling mode */
+#define MODE_DIRECT 4 /* Direct connection mode */
+#define MODE_DEDICATED 8 /* Dedicated line mode */
+
+#define EX_NORMAL 0
+#define EX_START 1
+#define EX_SOCK 2
+#define EX_MODEM 3
+#define EX_DIAL 4
+#define EX_DEAD 5
+#define EX_DONE 6
+#define EX_REBOOT 7
+#define EX_ERRDEAD 8
+#define EX_HANGUP 10
+#define EX_TERM 11
+
+int mode;
+
+int modem;
+int tun_in, tun_out;
+int netfd;
+char *dstsystem;
+
+#endif /* _DEFS_H_ */
diff --git a/usr.sbin/ppp/filter.c b/usr.sbin/ppp/filter.c
new file mode 100644
index 0000000..4240b6e
--- /dev/null
+++ b/usr.sbin/ppp/filter.c
@@ -0,0 +1,475 @@
+/*
+ * PPP Filter command Interface
+ *
+ * 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. 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: Shoud send ICMP error message when we discard packets.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include "command.h"
+#include "filter.h"
+
+static struct filterent filterdata;
+
+static u_long netmasks[33] = {
+ 0x00000000,
+ 0x80000000, 0xC0000000, 0xE0000000, 0xF0000000,
+ 0xF8000000, 0xFC000000, 0xFE000000, 0xFF000000,
+ 0xFF800000, 0xFFC00000, 0xFFE00000, 0xFFF00000,
+ 0xFFF80000, 0xFFFC0000, 0xFFFE0000, 0xFFFF0000,
+ 0xFFFF8000, 0xFFFFC000, 0xFFFFE000, 0xFFFFF000,
+ 0xFFFFF800, 0xFFFFFC00, 0xFFFFFE00, 0xFFFFFF00,
+ 0xFFFFFF80, 0xFFFFFFC0, 0xFFFFFFE0, 0xFFFFFFF0,
+ 0xFFFFFFF8, 0xFFFFFFFC, 0xFFFFFFFE, 0xFFFFFFFF,
+};
+
+int
+ParseAddr(argc, argv, paddr, pmask, pwidth)
+int argc;
+char **argv;
+struct in_addr *paddr;
+struct in_addr *pmask;
+int *pwidth;
+{
+ u_long addr;
+ int bits;
+ char *cp, *wp;
+
+ if (argc < 1) {
+#ifdef notdef
+ printf("address/mask is expected.\n");
+#endif
+ return(0);
+ }
+
+ pmask->s_addr = -1; /* Assume 255.255.255.255 as default */
+ cp = index(*argv, '/');
+ if (cp) *cp++ = '\0';
+ addr = inet_addr(*argv);
+ paddr->s_addr = addr;
+ if (cp && *cp) {
+ bits = strtol(cp, &wp, 0);
+ if (cp == wp || bits < 0 || bits > 32) {
+ printf("bad mask width.\n");
+ return(0);
+ }
+ } else {
+ /* if width is not given, assume whole 32 bits are meaningfull */
+ bits = 32;
+ }
+
+ *pwidth = bits;
+ pmask->s_addr = htonl(netmasks[bits]);
+
+ return(1);
+}
+
+static int
+ParseProto(argc, argv)
+int argc;
+char **argv;
+{
+ int proto;
+
+ if (argc < 1)
+ return(P_NONE);
+
+ if (STREQ(*argv, "tcp"))
+ proto = P_TCP;
+ else if (STREQ(*argv, "udp"))
+ proto = P_UDP;
+ else if (STREQ(*argv, "icmp"))
+ proto = P_ICMP;
+ else
+ proto = P_NONE;
+ return(proto);
+}
+
+/*
+ * ICMP Syntax: src eq icmp_message_type
+ */
+static int
+ParseIcmp(argc, argv)
+int argc;
+char **argv;
+{
+ int type;
+ char *cp;
+
+ switch (argc) {
+ case 0:
+ /* permit/deny all ICMP types */
+ filterdata.opt.srcop = OP_NONE;
+ break;
+ default:
+ printf("bad icmp syntax.\n");
+ return(0);
+ case 3:
+ if (STREQ(*argv, "src") && STREQ(argv[1], "eq")) {
+ type = strtol(argv[2], &cp, 0);
+ if (cp == argv[2]) {
+ printf("type is expected.\n");
+ return(0);
+ }
+ filterdata.opt.srcop = OP_EQ;
+ filterdata.opt.srcport = type;
+ }
+ break;
+ }
+ return(1);
+}
+
+static int
+ParseOp(cp)
+char *cp;
+{
+ int op = OP_NONE;
+
+ if (STREQ(cp, "eq"))
+ op = OP_EQ;
+ else if (STREQ(cp, "gt"))
+ op = OP_GT;
+ else if (STREQ(cp, "lt"))
+ op = OP_LT;
+ return(op);
+}
+
+/*
+ * UDP Syntax: [src op port] [dst op port]
+ */
+static int
+ParseUdp(argc, argv)
+int argc;
+char **argv;
+{
+ int port;
+ char *cp;
+
+ if (argc == 0) {
+ /* permit/deny all tcp traffic */
+ filterdata.opt.srcop = filterdata.opt.dstop = A_NONE;
+ return(1);
+ }
+ if (argc < 3) {
+#ifdef notdef
+ printf("bad udp syntax.\n");
+#endif
+ return(0);
+ }
+ if (STREQ(*argv, "src")) {
+ filterdata.opt.srcop = ParseOp(argv[1]);
+ if (filterdata.opt.srcop == OP_NONE) {
+ printf("bad operation\n");
+ return(0);
+ }
+ port = strtol(argv[2], &cp, 0);
+ if (cp == argv[2]) {
+ printf("expect port number.\n");
+ return(0);
+ }
+ filterdata.opt.srcport = port;
+ argc -= 3; argv += 3;
+ if (argc == 0)
+ return(1);
+ }
+
+ if (argc >= 3 && STREQ(argv[0], "dst")) {
+ filterdata.opt.dstop = ParseOp(argv[1]);
+ if (filterdata.opt.dstop == OP_NONE) {
+ printf("bad operation\n");
+ return(0);
+ }
+ port = strtol(argv[2], &cp, 0);
+ if (cp == argv[2]) {
+ printf("port number is expected.\n");
+ return(0);
+ }
+ filterdata.opt.dstport = port;
+ return(1);
+ }
+ if (argc == 1 && STREQ(argv[0], "estab"))
+ return(1);
+ printf("no src/dst port.\n");
+ return(0);
+}
+
+/*
+ * TCP Syntax: [src op port] [dst op port] [estab]
+ */
+static int
+ParseTcp(argc, argv)
+int argc;
+char **argv;
+{
+ int val;
+
+ val = ParseUdp(argc, argv);
+ if (val) {
+ if (argc == 0) return(1); /* Will permit/deny all tcp traffic */
+ argc -= 3; argv += 3;
+ if (argc > 1) {
+ argc -= 3; argv += 3;
+ }
+ if (argc < 0 || argc > 1) {
+ printf("bad tcp syntax.\n");
+ return(0);
+ }
+ if (argc == 1) {
+checkestab:
+ if (STREQ(*argv, "estab")) {
+ filterdata.opt.estab = 1;
+ return(1);
+ }
+ printf("estab is expected.\n");
+ return(0);
+ }
+
+ return(1);
+ } else if (argc == 1)
+ goto checkestab;
+ printf("bad port syntax (val = %d, argc = %d.\n", val, argc);
+ return(0);
+}
+
+char *opname[] = { "none", "eq", "gt", "lt" };
+
+static int
+Parse(argc, argv, ofp)
+int argc;
+char **argv;
+struct filterent *ofp;
+{
+ int action, proto;
+ int val;
+ char *wp;
+ struct filterent *fp = &filterdata;
+
+ val = strtol(*argv, &wp, 0);
+ if (*argv == wp || val > MAXFILTERS) {
+ printf("invalid filter number.\n");
+ return(0);
+ }
+ if (val < 0) {
+ for (val = 0; val < MAXFILTERS; val++) {
+ ofp->action = A_NONE;
+ ofp++;
+ }
+ printf("filter cleard.\n");
+ return(1);
+ }
+ ofp += val;
+
+ if (--argc == 0) {
+ printf("missing action.\n");
+ return(0);
+ }
+ argv++;
+
+ proto = P_NONE;
+ bzero(&filterdata, sizeof(filterdata));
+
+ if (STREQ(*argv, "permit")) {
+ action = A_PERMIT;
+ } else if (STREQ(*argv, "deny")) {
+ action = A_DENY;
+ } else if (STREQ(*argv, "clear")) {
+ ofp->action = A_NONE;
+ return(1);
+ } else {
+ printf("bad action: %s\n", *argv);
+ return(0);
+ }
+ fp->action = action;
+
+ argc--; argv++;
+
+ if (ofp->action == A_DENY) {
+ if (STREQ(*argv, "host")) {
+ fp->action |= A_UHOST;
+ argc--; argv++;
+ } else if (STREQ(*argv, "port")) {
+ fp->action |= A_UPORT;
+ argc--; argv++;
+ }
+ }
+
+ fp->proto = proto = ParseProto(argc, argv);
+ if (proto == P_NONE) {
+ if (ParseAddr(argc, argv, &fp->saddr, &fp->smask, &fp->swidth)) {
+ argc--; argv++;
+ proto = ParseProto(argc, argv);
+ if (proto == P_NONE) {
+ if (ParseAddr(argc, argv, &fp->daddr, &fp->dmask, &fp->dwidth)) {
+ argc--; argv++;
+ }
+ proto = ParseProto(argc, argv);
+ if (proto) {
+ argc--; argv++;
+ }
+ }
+ } else {
+ printf("Address/protocol expected.\n");
+ return(0);
+ }
+ } else {
+ argc--; argv++;
+ }
+
+ val = 1;
+
+ switch (proto) {
+ case P_TCP:
+ val = ParseTcp(argc, argv);
+ break;
+ case P_UDP:
+ val = ParseUdp(argc, argv);
+ break;
+ case P_ICMP:
+ val = ParseIcmp(argc, argv);
+ break;
+ }
+
+#ifdef DEBUG
+ printf("src: %s/", inet_ntoa(fp->saddr));
+ printf("%s ", inet_ntoa(fp->smask));
+ printf("dst: %s/", inet_ntoa(fp->daddr));
+ printf("%s proto = %d\n", inet_ntoa(fp->dmask), proto);
+
+ printf("src: %s (%d)\n", opname[fp->opt.srcop], fp->opt.srcport);
+ printf("dst: %s (%d)\n", opname[fp->opt.dstop], fp->opt.dstport);
+ printf("estab: %d\n", fp->opt.estab);
+#endif
+
+ if (val)
+ *ofp = *fp;
+ return(val);
+}
+
+int
+SetIfilter(list, argc, argv)
+struct cmdtab *list;
+int argc;
+char **argv;
+{
+ if (argc > 0)
+ (void) Parse(argc, argv, ifilters);
+ else
+ printf("syntax error.\n");
+
+ return(1);
+}
+
+int
+SetOfilter(list, argc, argv)
+struct cmdtab *list;
+int argc;
+char **argv;
+{
+ if (argc > 0)
+ (void) Parse(argc, argv, ofilters);
+ else
+ printf("syntax error.\n");
+ return(1);
+}
+
+int
+SetDfilter(list, argc, argv)
+struct cmdtab *list;
+int argc;
+char **argv;
+{
+ if (argc > 0)
+ (void) Parse(argc, argv, dfilters);
+ else
+ printf("syntax error.\n");
+ return(1);
+}
+
+static char *protoname[] = {
+ "none", "tcp", "udp", "icmp",
+};
+
+static char *actname[] = {
+ "none ", "permit ", "deny ",
+};
+
+static void
+ShowFilter(fp)
+struct filterent *fp;
+{
+ int n;
+
+ for (n = 0; n < MAXFILTERS; n++, fp++) {
+ if (fp->action != A_NONE) {
+ printf("%2d %s", n, actname[fp->action]);
+
+ printf("%s/%d ", inet_ntoa(fp->saddr), fp->swidth);
+ printf("%s/%d ", inet_ntoa(fp->daddr), fp->dwidth);
+ if (fp->proto) {
+ printf("%s", protoname[fp->proto]);
+
+ if (fp->opt.srcop)
+ printf(" src %s %d", opname[fp->opt.srcop], fp->opt.srcport);
+ if (fp->opt.dstop)
+ printf(" dst %s %d", opname[fp->opt.dstop], fp->opt.dstport);
+ if (fp->opt.estab)
+ printf(" estab");
+
+ }
+ printf("\n");
+ }
+ }
+}
+
+int
+ShowIfilter(list, argc, argv)
+struct cmdtab *list;
+int argc;
+char **argv;
+{
+ ShowFilter(ifilters);
+ return(1);
+}
+
+int
+ShowOfilter(list, argc, argv)
+struct cmdtab *list;
+int argc;
+char **argv;
+{
+ ShowFilter(ofilters);
+ return(1);
+}
+
+int
+ShowDfilter(list, argc, argv)
+struct cmdtab *list;
+int argc;
+char **argv;
+{
+ ShowFilter(dfilters);
+ return(1);
+}
diff --git a/usr.sbin/ppp/filter.h b/usr.sbin/ppp/filter.h
new file mode 100644
index 0000000..9e6a39d
--- /dev/null
+++ b/usr.sbin/ppp/filter.h
@@ -0,0 +1,77 @@
+/*
+ * 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. 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:
+ */
+
+#ifndef _FILTER_H_
+#define _FILTER_H_
+
+#define STREQ(a,b) (strcmp(a,b) == 0)
+/*
+ * Actions
+ */
+#define A_NONE 0
+#define A_PERMIT 1
+#define A_DENY 2
+#define A_MASK 3
+#define A_UHOST 4
+#define A_UPORT 8
+
+/*
+ * Known protocols
+ */
+#define P_NONE 0
+#define P_TCP 1
+#define P_UDP 2
+#define P_ICMP 3
+
+/*
+ * Operations
+ */
+#define OP_NONE 0
+#define OP_EQ 1
+#define OP_GT 2
+#define OP_LT 4
+
+struct filterent {
+ int action; /* Filtering action */
+ int swidth; /* Effective source address width */
+ struct in_addr saddr; /* Source address */
+ struct in_addr smask; /* Source address mask */
+ int dwidth; /* Effective destination address width */
+ struct in_addr daddr; /* Destination address */
+ struct in_addr dmask; /* Destination address mask */
+ int proto; /* Protocol */
+ struct {
+ short srcop;
+ u_short srcport;
+ short dstop;
+ u_short dstport;
+ int estab;
+ } opt;
+};
+
+#define MAXFILTERS 20
+
+struct filterent ifilters[MAXFILTERS];
+struct filterent ofilters[MAXFILTERS];
+struct filterent dfilters[MAXFILTERS];
+
+#endif _FILTER_H_
diff --git a/usr.sbin/ppp/fsm.c b/usr.sbin/ppp/fsm.c
new file mode 100644
index 0000000..89f9151
--- /dev/null
+++ b/usr.sbin/ppp/fsm.c
@@ -0,0 +1,802 @@
+/*
+ * PPP Finite State Machine for LCP/IPCP
+ *
+ * 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 Refer loglevel for log output
+ * o Better option log display
+ */
+#include "fsm.h"
+#include "hdlc.h"
+#include "lqr.h"
+#include "lcpproto.h"
+#include "lcp.h"
+
+void FsmSendConfigReq(struct fsm *fp);
+void FsmSendTerminateReq(struct fsm *fp);
+void FsmInitRestartCounter(struct fsm *fp);
+void FsmTimeout(struct fsm *fp);
+
+char *StateNames[] = {
+ "Initial", "Starting", "Closed", "Stopped", "Closing", "Stopping",
+ "Req-Sent", "Ack-Rcvd", "Ack-Sent", "Opend",
+};
+
+void
+FsmInit(fp)
+struct fsm *fp;
+{
+#ifdef DEBUG
+ logprintf("FsmInit\n");
+#endif
+ fp->state = ST_INITIAL;
+ fp->reqid = 1;
+ fp->restart = 1;
+ fp->maxconfig = 3;
+}
+
+void
+NewState(fp, new)
+struct fsm *fp;
+int new;
+{
+ LogPrintf(LOG_LCP, "%s: state change %s --> %s\n",
+ fp->name, StateNames[fp->state], StateNames[new]);
+ fp->state = new;
+ if ((new >= ST_INITIAL && new <= ST_STOPPED) || (new == ST_OPENED))
+ StopTimer(&fp->FsmTimer);
+}
+
+void
+FsmOutput(fp, code, id, ptr, count)
+struct fsm *fp;
+u_int code, id;
+u_char *ptr;
+int count;
+{
+ int plen;
+ struct fsmheader lh;
+ struct mbuf *bp;
+
+ plen = sizeof(struct fsmheader) + count;
+ lh.code = code;
+ lh.id = id;
+ lh.length = htons(plen);
+ bp = mballoc(plen, MB_FSM);
+ bcopy(&lh, MBUF_CTOP(bp), sizeof(struct fsmheader));
+ if (count)
+ bcopy(ptr, MBUF_CTOP(bp) + sizeof(struct fsmheader), count);
+#ifdef DEBUG
+ DumpBp(bp);
+#endif
+ HdlcOutput(PRI_NORMAL, fp->proto, bp);
+}
+
+void
+FsmOpen(fp)
+struct fsm *fp;
+{
+ switch (fp->state) {
+ case ST_INITIAL:
+ (fp->LayerStart)(fp);
+ NewState(fp, ST_STARTING);
+ break;
+ case ST_STARTING:
+ break;
+ case ST_CLOSED:
+ if (fp->open_mode == OPEN_PASSIVE) {
+ NewState(fp, ST_STOPPED);
+ } else {
+ FsmInitRestartCounter(fp);
+ FsmSendConfigReq(fp);
+ NewState(fp, ST_REQSENT);
+ }
+ break;
+ case ST_STOPPED: /* XXX: restart option */
+ case ST_REQSENT:
+ case ST_ACKRCVD:
+ case ST_ACKSENT:
+ case ST_OPENED: /* XXX: restart option */
+ break;
+ case ST_CLOSING: /* XXX: restart option */
+ case ST_STOPPING: /* XXX: restart option */
+ NewState(fp, ST_STOPPING);
+ break;
+ }
+}
+
+void
+FsmUp(fp)
+struct fsm *fp;
+{
+ switch (fp->state) {
+ case ST_INITIAL:
+ NewState(fp, ST_CLOSED);
+ break;
+ case ST_STARTING:
+ FsmInitRestartCounter(fp);
+ FsmSendConfigReq(fp);
+ NewState(fp, ST_REQSENT);
+ break;
+ default:
+ LogPrintf(LOG_LCP, "%s: Oops, Up at %s\n",
+ fp->name, StateNames[fp->state]);
+ break;
+ }
+}
+
+void
+FsmDown(fp)
+struct fsm *fp;
+{
+ switch (fp->state) {
+ case ST_CLOSED:
+ case ST_CLOSING:
+ NewState(fp, ST_INITIAL);
+ break;
+ case ST_STOPPED:
+ (fp->LayerStart)(fp);
+ /* Fall into.. */
+ case ST_STOPPING:
+ case ST_REQSENT:
+ case ST_ACKRCVD:
+ case ST_ACKSENT:
+ NewState(fp, ST_STARTING);
+ break;
+ case ST_OPENED:
+ (fp->LayerDown)(fp);
+ NewState(fp, ST_STARTING);
+ break;
+ }
+}
+
+void
+FsmClose(fp)
+struct fsm *fp;
+{
+ switch (fp->state) {
+ case ST_STARTING:
+ NewState(fp, ST_INITIAL);
+ break;
+ case ST_STOPPED:
+ NewState(fp, ST_CLOSED);
+ break;
+ case ST_STOPPING:
+ NewState(fp, ST_CLOSING);
+ break;
+ case ST_OPENED:
+ (fp->LayerDown)(fp);
+ /* Fall down */
+ case ST_REQSENT:
+ case ST_ACKRCVD:
+ case ST_ACKSENT:
+ FsmInitRestartCounter(fp);
+ FsmSendTerminateReq(fp);
+ NewState(fp, ST_CLOSING);
+ break;
+ }
+}
+
+/*
+ * Send functions
+ */
+void
+FsmSendConfigReq(fp)
+struct fsm *fp;
+{
+ if (--fp->maxconfig > 0) {
+ (fp->SendConfigReq)(fp);
+ StartTimer(&fp->FsmTimer); /* Start restart timer */
+ fp->restart--; /* Decrement restart counter */
+ } else {
+ FsmClose(fp);
+ }
+}
+
+void
+FsmSendTerminateReq(fp)
+struct fsm *fp;
+{
+ LogPrintf(LOG_LCP, "%s: SendTerminateReq.\n", fp->name);
+ FsmOutput(fp, CODE_TERMREQ, fp->reqid++, NULL, 0);
+ (fp->SendTerminateReq)(fp);
+ StartTimer(&fp->FsmTimer); /* Start restart timer */
+ fp->restart--; /* Decrement restart counter */
+}
+
+static void
+FsmSendConfigAck(fp, lhp, option, count)
+struct fsm *fp;
+struct fsmheader *lhp;
+u_char *option;
+int count;
+{
+ LogPrintf(LOG_LCP, "%s: SendConfigAck(%s)\n", fp->name, StateNames[fp->state]);
+ FsmOutput(fp, CODE_CONFIGACK, lhp->id, option, count);
+}
+
+static void
+FsmSendConfigRej(fp, lhp, option, count)
+struct fsm *fp;
+struct fsmheader *lhp;
+u_char *option;
+int count;
+{
+ LogPrintf(LOG_LCP, "%s: SendConfigRej(%s)\n", fp->name, StateNames[fp->state]);
+ FsmOutput(fp, CODE_CONFIGREJ, lhp->id, option, count);
+}
+
+static void
+FsmSendConfigNak(fp, lhp, option, count)
+struct fsm *fp;
+struct fsmheader *lhp;
+u_char *option;
+int count;
+{
+ LogPrintf(LOG_LCP, "%s: SendConfigNak(%s)\n",
+ fp->name, StateNames[fp->state]);
+ FsmOutput(fp, CODE_CONFIGNAK, lhp->id, option, count);
+}
+
+/*
+ * Timeout actions
+ */
+void
+FsmTimeout(fp)
+struct fsm *fp;
+{
+ if (fp->restart) {
+ switch (fp->state) {
+ case ST_CLOSING:
+ case ST_STOPPING:
+ FsmSendTerminateReq(fp);
+ break;
+ case ST_REQSENT:
+ case ST_ACKSENT:
+ FsmSendConfigReq(fp);
+ break;
+ case ST_ACKRCVD:
+ FsmSendConfigReq(fp);
+ NewState(fp, ST_REQSENT);
+ break;
+ }
+ StartTimer(&fp->FsmTimer);
+ } else {
+ switch (fp->state) {
+ case ST_CLOSING:
+ NewState(fp, ST_CLOSED);
+ (fp->LayerFinish)(fp);
+ break;
+ case ST_STOPPING:
+ NewState(fp, ST_STOPPED);
+ (fp->LayerFinish)(fp);
+ break;
+ case ST_REQSENT: /* XXX: 3p */
+ case ST_ACKSENT:
+ case ST_ACKRCVD:
+ NewState(fp, ST_STOPPED);
+ (fp->LayerFinish)(fp);
+ break;
+ }
+ }
+}
+
+void
+FsmInitRestartCounter(fp)
+struct fsm *fp;
+{
+ StopTimer(&fp->FsmTimer);
+ fp->FsmTimer.state = TIMER_STOPPED;
+ fp->FsmTimer.func = FsmTimeout;
+ fp->FsmTimer.arg = (void *)fp;
+ (fp->InitRestartCounter)(fp);
+}
+
+/*
+ * Actions when receive packets
+ */
+void
+FsmRecvConfigReq(fp, lhp, bp) /* RCR */
+struct fsm *fp;
+struct fsmheader *lhp;
+struct mbuf *bp;
+{
+ int plen;
+ int ackaction = 0;
+
+ plen = plength(bp);
+ if (plen < sizeof(struct fsmconfig)) {
+logprintf("** plen = %d\n", plen);
+ pfree(bp);
+ return;
+ }
+
+ /*
+ * Check and process easy case
+ */
+ switch (fp->state) {
+ case ST_INITIAL:
+ case ST_STARTING:
+ LogPrintf(LOG_LCP, "%s: Oops, RCR in %s.\n",
+ fp->name, StateNames[fp->state]);
+ pfree(bp);
+ return;
+ case ST_CLOSED:
+ (fp->SendTerminateAck)(fp);
+ pfree(bp);
+ return;
+ case ST_CLOSING:
+ case ST_STOPPING:
+logprintf("## state = %d\n", fp->state);
+ pfree(bp);
+ return;
+ }
+
+ (fp->DecodeConfig)(bp, MODE_REQ);
+
+ if (nakp == NakBuff && rejp == RejBuff)
+ ackaction = 1;
+
+ switch (fp->state) {
+ case ST_OPENED:
+ (fp->LayerDown)(fp);
+ FsmSendConfigReq(fp);
+ break;
+ case ST_STOPPED:
+ FsmInitRestartCounter(fp);
+ FsmSendConfigReq(fp);
+ break;
+ }
+
+ if (rejp != RejBuff)
+ FsmSendConfigRej(fp, lhp, RejBuff, rejp - RejBuff);
+ if (nakp != NakBuff)
+ FsmSendConfigNak(fp, lhp, NakBuff, nakp - NakBuff);
+ if (ackaction)
+ FsmSendConfigAck(fp, lhp, AckBuff, ackp - AckBuff);
+
+ switch (fp->state) {
+ case ST_STOPPED:
+ case ST_OPENED:
+ if (ackaction)
+ NewState(fp, ST_ACKSENT);
+ else
+ NewState(fp, ST_REQSENT);
+ break;
+ case ST_REQSENT:
+ if (ackaction)
+ NewState(fp, ST_ACKSENT);
+ break;
+ case ST_ACKRCVD:
+ if (ackaction) {
+ NewState(fp, ST_OPENED);
+ (fp->LayerUp)(fp);
+ }
+ break;
+ case ST_ACKSENT:
+ if (!ackaction)
+ NewState(fp, ST_REQSENT);
+ break;
+ }
+ pfree(bp);
+}
+
+void
+FsmRecvConfigAck(fp, lhp, bp) /* RCA */
+struct fsm *fp;
+struct fsmheader *lhp;
+struct mbuf *bp;
+{
+ switch (fp->state) {
+ case ST_CLOSED:
+ case ST_STOPPED:
+ (fp->SendTerminateAck)(fp);
+ break;
+ case ST_CLOSING:
+ case ST_STOPPING:
+ break;
+ case ST_REQSENT:
+ FsmInitRestartCounter(fp);
+ NewState(fp, ST_ACKRCVD);
+ break;
+ case ST_ACKRCVD:
+ FsmSendConfigReq(fp);
+ NewState(fp, ST_REQSENT);
+ break;
+ case ST_ACKSENT:
+ FsmInitRestartCounter(fp);
+ NewState(fp, ST_OPENED);
+ (fp->LayerUp)(fp);
+ break;
+ case ST_OPENED:
+ (fp->LayerDown)(fp);
+ FsmSendConfigReq(fp);
+ NewState(fp, ST_REQSENT);
+ break;
+ }
+ pfree(bp);
+}
+
+void
+FsmRecvConfigNak(fp, lhp, bp) /* RCN */
+struct fsm *fp;
+struct fsmheader *lhp;
+struct mbuf *bp;
+{
+ int plen;
+
+ plen = plength(bp);
+ if (plen < sizeof(struct fsmconfig)) {
+ pfree(bp);
+ return;
+ }
+
+ /*
+ * Check and process easy case
+ */
+ switch (fp->state) {
+ case ST_INITIAL:
+ case ST_STARTING:
+ LogPrintf(LOG_LCP, "%s: Oops, RCN in %s.\n",
+ fp->name, StateNames[fp->state]);
+ pfree(bp);
+ return;
+ case ST_CLOSED:
+ case ST_STOPPED:
+ (fp->SendTerminateAck)(fp);
+ pfree(bp);
+ return;
+ case ST_CLOSING:
+ case ST_STOPPING:
+ pfree(bp);
+ return;
+ }
+
+ (fp->DecodeConfig)(bp, MODE_NAK);
+
+ switch (fp->state) {
+ case ST_REQSENT:
+ case ST_ACKSENT:
+ FsmInitRestartCounter(fp);
+ FsmSendConfigReq(fp);
+ break;
+ case ST_OPENED:
+ (fp->LayerDown)(fp);
+ /* Fall down */
+ case ST_ACKRCVD:
+ FsmSendConfigReq(fp);
+ NewState(fp, ST_REQSENT);
+ break;
+ }
+
+ pfree(bp);
+}
+
+void
+FsmRecvTermReq(fp, lhp, bp) /* RTR */
+struct fsm *fp;
+struct fsmheader *lhp;
+struct mbuf *bp;
+{
+ switch (fp->state) {
+ case ST_INITIAL:
+ case ST_STARTING:
+ LogPrintf(LOG_LCP, "%s: Oops, RTR in %s\n", fp->name,
+ StateNames[fp->state]);
+ break;
+ case ST_CLOSED:
+ case ST_STOPPED:
+ case ST_CLOSING:
+ case ST_STOPPING:
+ case ST_REQSENT:
+ (fp->SendTerminateAck)(fp);
+ break;
+ case ST_ACKRCVD:
+ case ST_ACKSENT:
+ (fp->SendTerminateAck)(fp);
+ NewState(fp, ST_REQSENT);
+ break;
+ case ST_OPENED:
+ (fp->LayerDown)(fp);
+ /* Zero Restart counter */
+ (fp->SendTerminateAck)(fp);
+ NewState(fp, ST_STOPPING);
+ break;
+ }
+ pfree(bp);
+}
+
+void
+FsmRecvTermAck(fp, lhp, bp) /* RTA */
+struct fsm *fp;
+struct fsmheader *lhp;
+struct mbuf *bp;
+{
+ switch (fp->state) {
+ case ST_CLOSING:
+ NewState(fp, ST_CLOSED);
+ (fp->LayerFinish)(fp);
+ break;
+ case ST_STOPPING:
+ NewState(fp, ST_STOPPED);
+ (fp->LayerFinish)(fp);
+ break;
+ case ST_ACKRCVD:
+ NewState(fp, ST_REQSENT);
+ break;
+ case ST_OPENED:
+ (fp->LayerDown)(fp);
+ FsmSendConfigReq(fp);
+ NewState(fp, ST_REQSENT);
+ break;
+ }
+ pfree(bp);
+}
+
+void
+FsmRecvConfigRej(fp, lhp, bp) /* RCJ */
+struct fsm *fp;
+struct fsmheader *lhp;
+struct mbuf *bp;
+{
+ int plen;
+
+ plen = plength(bp);
+ if (plen < sizeof(struct fsmconfig)) {
+ pfree(bp);
+ return;
+ }
+ LogPrintf(LOG_LCP, "%s: RecvConfigRej.\n", fp->name);
+
+ /*
+ * Check and process easy case
+ */
+ switch (fp->state) {
+ case ST_INITIAL:
+ case ST_STARTING:
+ LogPrintf(LOG_LCP, "%s: Oops, RCJ in %s.\n",
+ fp->name, StateNames[fp->state]);
+ pfree(bp);
+ return;
+ case ST_CLOSED:
+ case ST_STOPPED:
+ (fp->SendTerminateAck)(fp);
+ pfree(bp);
+ return;
+ case ST_CLOSING:
+ case ST_STOPPING:
+ pfree(bp);
+ return;
+ }
+
+ (fp->DecodeConfig)(bp, MODE_REJ);
+
+ switch (fp->state) {
+ case ST_REQSENT:
+ case ST_ACKSENT:
+ FsmInitRestartCounter(fp);
+ FsmSendConfigReq(fp);
+ break;
+ case ST_OPENED:
+ (fp->LayerDown)(fp);
+ /* Fall down */
+ case ST_ACKRCVD:
+ FsmSendConfigReq(fp);
+ NewState(fp, ST_REQSENT);
+ break;
+ }
+ pfree(bp);
+}
+
+void
+FsmRecvCodeRej(fp, lhp, bp)
+struct fsm *fp;
+struct fsmheader *lhp;
+struct mbuf *bp;
+{
+ LogPrintf(LOG_LCP, "%s: RecvCodeRej\n", fp->name);
+ pfree(bp);
+}
+
+void
+FsmRecvProtoRej(fp, lhp, bp)
+struct fsm *fp;
+struct fsmheader *lhp;
+struct mbuf *bp;
+{
+ u_short *sp, proto;
+
+ sp = (u_short *)MBUF_CTOP(bp);
+ proto = ntohs(*sp);
+ LogPrintf(LOG_LCP, "-- Protocol (%04x) was rejected.\n", proto);
+
+ switch (proto) {
+ case PROTO_LQR:
+ StopLqr(LQM_LQR);
+ break;
+ case PROTO_CCP:
+ fp = &CcpFsm;
+ (fp->LayerFinish)(fp);
+ switch (fp->state) {
+ case ST_CLOSED:
+ case ST_CLOSING:
+ NewState(fp, ST_CLOSED);
+ default:
+ NewState(fp, ST_STOPPED);
+ break;
+ }
+ break;
+ }
+ pfree(bp);
+}
+
+void
+FsmRecvEchoReq(fp, lhp, bp)
+struct fsm *fp;
+struct fsmheader *lhp;
+struct mbuf *bp;
+{
+ u_char *cp;
+ u_long *lp, magic;
+
+ cp = MBUF_CTOP(bp);
+ lp = (u_long *)cp;
+ magic = ntohl(*lp);
+ if (magic != LcpInfo.his_magic) {
+ logprintf("RecvEchoReq: his magic is bad!!\n");
+ /* XXX: We should send terminate request */
+ }
+
+ if (fp->state == ST_OPENED) {
+ *lp = htonl(LcpInfo.want_magic); /* Insert local magic number */
+ LogPrintf(LOG_LCP, "%s: SendEchoRep(%s)\n", fp->name, StateNames[fp->state]);
+ FsmOutput(fp, CODE_ECHOREP, lhp->id, cp, plength(bp));
+ }
+ pfree(bp);
+}
+
+void
+FsmRecvEchoRep(fp, lhp, bp)
+struct fsm *fp;
+struct fsmheader *lhp;
+struct mbuf *bp;
+{
+ u_long *lp, magic;
+
+ lp = (u_long *)MBUF_CTOP(bp);
+ magic = ntohl(*lp);
+ if (magic != 0 && magic != LcpInfo.his_magic) {
+ logprintf("RecvEchoRep: his magic is wrong! expect: %x got: %x\n",
+ LcpInfo.his_magic, magic);
+ /*
+ * XXX: We should send terminate request. But poor implementation
+ * may die as a result.
+ */
+ }
+ RecvEchoLqr(bp);
+ pfree(bp);
+}
+
+void
+FsmRecvDiscReq(fp, lhp, bp)
+struct fsm *fp;
+struct fsmheader *lhp;
+struct mbuf *bp;
+{
+ LogPrintf(LOG_LCP, "%s: RecvDiscReq\n", fp->name);
+ pfree(bp);
+}
+
+void
+FsmRecvIdent(fp, lhp, bp)
+struct fsm *fp;
+struct fsmheader *lhp;
+struct mbuf *bp;
+{
+ LogPrintf(LOG_LCP, "%s: RecvIdent\n", fp->name);
+ pfree(bp);
+}
+
+void
+FsmRecvTimeRemain(fp, lhp, bp)
+struct fsm *fp;
+struct fsmheader *lhp;
+struct mbuf *bp;
+{
+ LogPrintf(LOG_LCP, "%s: RecvTimeRemain\n", fp->name);
+ pfree(bp);
+}
+
+void
+FsmRecvResetReq(fp, lhp, bp)
+struct fsm *fp;
+struct fsmheader *lhp;
+struct mbuf *bp;
+{
+ LogPrintf(LOG_LCP, "%s: RecvResetReq\n", fp->name);
+ CcpRecvResetReq(fp);
+ LogPrintf(LOG_LCP, "%s: SendResetAck\n", fp->name);
+ FsmOutput(fp, CODE_RESETACK, fp->reqid, NULL, 0);
+ pfree(bp);
+}
+
+void
+FsmRecvResetAck(fp, lhp, bp)
+struct fsm *fp;
+struct fsmheader *lhp;
+struct mbuf *bp;
+{
+ LogPrintf(LOG_LCP, "%s: RecvResetAck\n", fp->name);
+ fp->reqid++;
+ pfree(bp);
+}
+
+struct fsmcodedesc FsmCodes[] = {
+ { FsmRecvConfigReq, "Configure Request", },
+ { FsmRecvConfigAck, "Configure Ack", },
+ { FsmRecvConfigNak, "Configure Nak", },
+ { FsmRecvConfigRej, "Configure Reject", },
+ { FsmRecvTermReq, "Terminate Request", },
+ { FsmRecvTermAck, "Terminate Ack", },
+ { FsmRecvCodeRej, "Code Reject", },
+ { FsmRecvProtoRej, "Protocol Reject", },
+ { FsmRecvEchoReq, "Echo Request", },
+ { FsmRecvEchoRep, "Echo Reply", },
+ { FsmRecvDiscReq, "Discard Request", },
+ { FsmRecvIdent, "Ident", },
+ { FsmRecvTimeRemain, "Time Remain", },
+ { FsmRecvResetReq, "Reset Request", },
+ { FsmRecvResetAck, "Reset Ack", },
+};
+
+void
+FsmInput(fp, bp)
+struct fsm *fp;
+struct mbuf *bp;
+{
+ int len;
+ struct fsmheader *lhp;
+ struct fsmcodedesc *codep;
+
+ len = plength(bp);
+ if (len < sizeof(struct fsmheader)) {
+ pfree(bp);
+ return;
+ }
+ lhp = (struct fsmheader *)MBUF_CTOP(bp);
+ if (lhp->code == 0 || lhp->code > fp->max_code) {
+ pfree(bp); /* XXX: Should send code reject */
+ return;
+ }
+
+ bp->offset += sizeof(struct fsmheader);
+ bp->cnt -= sizeof(struct fsmheader);
+
+ codep = FsmCodes + lhp->code - 1;
+ LogPrintf(LOG_LCP, "%s: Received %s (%d) state = %s (%d)\n",
+ fp->name, codep->name, lhp->code, StateNames[fp->state], fp->state);
+#ifdef DEBUG
+ LogMemory();
+#endif
+ (codep->action)(fp, lhp, bp);
+#ifdef DEBUG
+ LogMemory();
+#endif
+}
diff --git a/usr.sbin/ppp/fsm.h b/usr.sbin/ppp/fsm.h
new file mode 100644
index 0000000..0a30ff1
--- /dev/null
+++ b/usr.sbin/ppp/fsm.h
@@ -0,0 +1,134 @@
+/*
+ * 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. 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:
+ */
+#ifndef _FSM_H_
+#define _FSM_H_
+
+#include "defs.h"
+#include <netinet/in.h>
+#include "timeout.h"
+
+/*
+ * State of machine
+ */
+#define ST_INITIAL 0
+#define ST_STARTING 1
+#define ST_CLOSED 2
+#define ST_STOPPED 3
+#define ST_CLOSING 4
+#define ST_STOPPING 5
+#define ST_REQSENT 6
+#define ST_ACKRCVD 7
+#define ST_ACKSENT 8
+#define ST_OPENED 9
+
+#define ST_MAX 10
+#define ST_UNDEF -1
+
+#define MODE_REQ 0
+#define MODE_NAK 1
+#define MODE_REJ 2
+
+#define OPEN_ACTIVE 0
+#define OPEN_PASSIVE 1
+
+struct fsm {
+ char *name; /* Name of protocol */
+ u_short proto; /* Protocol number */
+ u_short max_code;
+ int open_mode;
+ int state; /* State of the machine */
+ int reqid; /* Next request id */
+ int restart; /* Restart counter value */
+ int maxconfig;
+
+ int reqcode; /* Request code sent */
+ struct pppTimer FsmTimer; /* Restart Timer */
+
+ void (*LayerUp)();
+ void (*LayerDown)();
+ void (*LayerStart)();
+ void (*LayerFinish)();
+ void (*InitRestartCounter)();
+ void (*SendConfigReq)();
+ void (*SendTerminateReq)();
+ void (*SendTerminateAck)();
+ void (*DecodeConfig)();
+};
+
+struct fsmheader {
+ u_char code; /* Request code */
+ u_char id; /* Identification */
+ u_short length; /* Length of packet */
+};
+
+#define CODE_CONFIGREQ 1
+#define CODE_CONFIGACK 2
+#define CODE_CONFIGNAK 3
+#define CODE_CONFIGREJ 4
+#define CODE_TERMREQ 5
+#define CODE_TERMACK 6
+#define CODE_CODEREJ 7
+#define CODE_PROTOREJ 8
+#define CODE_ECHOREQ 9 /* Used in LCP */
+#define CODE_ECHOREP 10 /* Used in LCP */
+#define CODE_DISCREQ 11
+#define CODE_IDENT 12 /* Used in LCP Extension */
+#define CODE_TIMEREM 13 /* Used in LCP Extension */
+#define CODE_RESETREQ 14 /* Used in CCP */
+#define CODE_RESETACK 15 /* Used in CCP */
+
+struct fsmcodedesc {
+ void (*action)();
+ char *name;
+};
+
+struct fsmconfig {
+ u_char type;
+ u_char length;
+};
+
+u_char AckBuff[200];
+u_char NakBuff[200];
+u_char RejBuff[100];
+u_char ReqBuff[200];
+
+u_char *ackp, *nakp, *rejp;
+
+extern char *StateNames[];
+extern void FsmInit(struct fsm *);
+extern void NewState(struct fsm *, int);
+extern void FsmOutput(struct fsm *, u_int, u_int, u_char *, int);
+extern void FsmOpen(struct fsm *);
+extern void FsmUp(struct fsm *);
+extern void FsmDown(struct fsm *);
+extern void FsmInput(struct fsm *, struct mbuf *);
+
+extern void FsmRecvConfigReq(struct fsm *, struct fsmheader *, struct mbuf *);
+extern void FsmRecvConfigAck(struct fsm *, struct fsmheader *, struct mbuf *);
+extern void FsmRecvConfigNak(struct fsm *, struct fsmheader *, struct mbuf *);
+extern void FsmRecvTermReq(struct fsm *, struct fsmheader *, struct mbuf *);
+extern void FsmRecvTermAck(struct fsm *, struct fsmheader *, struct mbuf *);
+extern void FsmClose(struct fsm *fp);
+
+extern struct fsm LcpFsm, IpcpFsm, CcpFsm;
+
+#endif /* _FSM_H_ */
diff --git a/usr.sbin/ppp/global.h b/usr.sbin/ppp/global.h
new file mode 100644
index 0000000..5eb6034
--- /dev/null
+++ b/usr.sbin/ppp/global.h
@@ -0,0 +1,51 @@
+/*
+ * GLOBAL.H - RSAREF types and constants
+ *
+ * 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. 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:
+ */
+
+/* PROTOTYPES should be set to one if and only if the compiler supports
+ function argument prototyping.
+ The following makes PROTOTYPES default to 0 if it has not already
+ been defined with C compiler flags.
+ */
+#ifndef PROTOTYPES
+#define PROTOTYPES 0
+#endif
+
+/* POINTER defines a generic pointer type */
+typedef unsigned char *POINTER;
+
+/* UINT2 defines a two byte word */
+typedef unsigned short int UINT2;
+
+/* UINT4 defines a four byte word */
+typedef unsigned long int UINT4;
+
+/* PROTO_LIST is defined depending on how PROTOTYPES is defined above.
+If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it
+ returns an empty list.
+ */
+#if PROTOTYPES
+#define PROTO_LIST(list) list
+#else
+#define PROTO_LIST(list) ()
+#endif
diff --git a/usr.sbin/ppp/hdlc.c b/usr.sbin/ppp/hdlc.c
new file mode 100644
index 0000000..9791ee1
--- /dev/null
+++ b/usr.sbin/ppp/hdlc.c
@@ -0,0 +1,378 @@
+/*
+ * PPP High Level Link Control (HDLC) 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:
+ */
+#include "fsm.h"
+#include "hdlc.h"
+#include "lcpproto.h"
+#include "lcp.h"
+#include "lqr.h"
+
+struct hdlcstat {
+ int badfcs;
+ int badaddr;
+ int badcommand;
+ int unknownproto;
+} HdlcStat;
+
+static int ifOutPackets, ifOutOctets, ifOutLQRs;
+static int ifInPackets, ifInOctets;
+
+struct protostat {
+ u_short number;
+ char *name;
+ u_long in_count;
+ u_long out_count;
+} ProtocolStat[] = {
+ { PROTO_IP, "IP" },
+ { PROTO_VJUNCOMP, "VJ_UNCOMP" },
+ { PROTO_VJCOMP, "VJ_COMP" },
+ { PROTO_COMPD, "COMPD" },
+ { PROTO_LCP, "LCP" },
+ { PROTO_IPCP, "IPCP" },
+ { PROTO_CCP, "CCP" },
+ { PROTO_PAP, "PAP" },
+ { PROTO_LQR, "LQR" },
+ { PROTO_CHAP, "CHAP" },
+ { 0, "Others" },
+};
+
+static u_short fcstab[256] = {
+/* 00 */ 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
+/* 08 */ 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
+/* 10 */ 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
+/* 18 */ 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
+/* 20 */ 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
+/* 28 */ 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
+/* 30 */ 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
+/* 38 */ 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
+/* 40 */ 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
+/* 48 */ 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
+/* 50 */ 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
+/* 58 */ 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
+/* 60 */ 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
+/* 68 */ 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
+/* 70 */ 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
+/* 78 */ 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
+/* 80 */ 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
+/* 88 */ 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
+/* 90 */ 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
+/* 98 */ 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
+/* a0 */ 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
+/* a8 */ 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
+/* b0 */ 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
+/* b8 */ 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
+/* c0 */ 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
+/* c8 */ 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
+/* d0 */ 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
+/* d8 */ 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
+/* e0 */ 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
+/* e8 */ 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
+/* f0 */ 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
+/* f8 */ 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
+};
+
+void
+HdlcInit()
+{
+ ifInOctets = ifOutOctets = 0;
+ ifInPackets = ifOutPackets = 0;
+ ifOutLQRs = 0;
+}
+
+/*
+ * HDLC FCS computation. Read RFC 1171 Appendix B and CCITT X.25 section
+ * 2.27 for further details.
+ */
+u_short
+HdlcFcs(fcs, cp, len)
+u_short fcs;
+u_char *cp;
+int len;
+{
+ while (len--)
+ fcs = (fcs >> 8) ^ fcstab[(fcs ^ *cp++) & 0xff];
+ return(fcs);
+}
+
+void
+HdlcOutput(int pri, u_short proto, struct mbuf *bp)
+{
+ struct mbuf *mhp, *mfcs;
+ struct protostat *statp;
+ struct lqrdata *lqr;
+ u_char *cp;
+ u_short fcs;
+
+ if ((proto & 0xfff1) == 0x21) { /* Network Layer protocol */
+ if (CcpFsm.state == ST_OPENED) {
+ Pred1Output(pri, proto, bp);
+ return;
+ }
+ }
+ mfcs = mballoc(2, MB_HDLCOUT);
+ mhp = mballoc(4, MB_HDLCOUT);
+ mhp->cnt = 0;
+ cp = MBUF_CTOP(mhp);
+ if (proto == PROTO_LCP || LcpInfo.his_acfcomp == 0) {
+ *cp++ = HDLC_ADDR;
+ *cp++ = HDLC_UI;
+ mhp->cnt += 2;
+ }
+ /*
+ * If possible, compress protocol field.
+ */
+ if (LcpInfo.his_protocomp && (proto & 0xff00) == 0) {
+ *cp++ = proto;
+ mhp->cnt++;
+ } else {
+ *cp++ = proto >> 8;
+ *cp = proto & 0377;
+ mhp->cnt += 2;
+ }
+ mhp->next = bp;
+ bp->next = mfcs;
+
+ lqr = &MyLqrData;
+ lqr->PeerOutPackets = ifOutPackets++;
+ ifOutOctets += plength(mhp) + 1;
+ lqr->PeerOutOctets = ifOutOctets;
+
+ if (proto == PROTO_LQR) {
+ lqr->MagicNumber = LcpInfo.want_magic;
+ lqr->LastOutLQRs = HisLqrData.PeerOutLQRs;
+ lqr->LastOutPackets = HisLqrData.PeerOutPackets;
+ lqr->LastOutOctets = HisLqrData.PeerOutOctets;
+ lqr->PeerInLQRs = HisLqrSave.SaveInLQRs;
+ lqr->PeerInPackets = HisLqrSave.SaveInPackets;
+ lqr->PeerInDiscards = HisLqrSave.SaveInDiscards;
+ lqr->PeerInErrors = HisLqrSave.SaveInErrors;
+ lqr->PeerInOctets = HisLqrSave.SaveInOctets;
+ lqr->PeerOutLQRs = ++ifOutLQRs;
+ LqrDump("LqrOutput", lqr);
+ LqrChangeOrder(lqr, (struct lqrdata *)(MBUF_CTOP(bp)));
+ }
+
+ fcs = HdlcFcs(INITFCS, MBUF_CTOP(mhp), mhp->cnt);
+ fcs = HdlcFcs(fcs, MBUF_CTOP(bp), bp->cnt);
+ fcs = ~fcs;
+ cp = MBUF_CTOP(mfcs);
+ *cp++ = fcs & 0377; /* Low byte first!! */
+ *cp++ = fcs >> 8;
+
+ LogDumpBp(LOG_HDLC, "HdlcOutput", mhp);
+ for (statp = ProtocolStat; statp->number; statp++)
+ if (statp->number == proto)
+ break;
+ statp->out_count++;
+ AsyncOutput(pri, mhp, proto);
+}
+
+DecodePacket(proto, bp)
+u_short proto;
+struct mbuf *bp;
+{
+#ifdef DEBUG
+ logprintf("proto = %04x\n", proto);
+#endif
+ switch (proto) {
+ case PROTO_LCP:
+ LcpInput(bp);
+ break;
+ case PROTO_PAP:
+ PapInput(bp);
+ break;
+ case PROTO_LQR:
+ HisLqrSave.SaveInLQRs++;
+ LqrInput(bp);
+ break;
+ case PROTO_CHAP:
+ ChapInput(bp);
+ break;
+ case PROTO_VJUNCOMP:
+ case PROTO_VJCOMP:
+ bp = VjCompInput(bp, proto);
+ /* fall down */
+ case PROTO_IP:
+ IpInput(bp);
+ break;
+ case PROTO_IPCP:
+ IpcpInput(bp);
+ break;
+ case PROTO_CCP:
+ CcpInput(bp);
+ break;
+ case PROTO_COMPD:
+ Pred1Input(bp);
+ break;
+ default:
+ logprintf("Unknown protocol 0x%04x\n", proto);
+ /*
+ * XXX: Should send protocol reject.
+ */
+ HisLqrSave.SaveInDiscards++;
+ HdlcStat.unknownproto++;
+ pfree(bp);
+ break;
+ }
+}
+
+int
+ReportProtStatus()
+{
+ struct protostat *statp;
+ int cnt;
+
+ statp = ProtocolStat;
+ statp--;
+ cnt = 0;
+ printf(" Protocol in out Protocol in out\n");
+ do {
+ statp++;
+ printf(" %-9s: %8u, %8u",
+ statp->name, statp->in_count, statp->out_count);
+ if (++cnt == 2) {
+ printf("\n");
+ cnt = 0;
+ }
+ } while (statp->number);
+ if (cnt)
+ printf("\n");
+ return(1);
+}
+
+int
+ReportHdlcStatus()
+{
+ struct hdlcstat *hp = &HdlcStat;
+
+ printf("HDLC level errors\n\n");
+ printf("FCS: %u ADDR: %u COMMAND: %u PROTO: %u\n",
+ hp->badfcs, hp->badaddr, hp->badcommand, hp->unknownproto);
+ return(1);
+}
+
+static struct hdlcstat laststat;
+
+void
+HdlcErrorCheck()
+{
+ struct hdlcstat *hp = &HdlcStat;
+ struct hdlcstat *op = &laststat;
+
+ if (bcmp(hp, op, sizeof(laststat))) {
+ LogPrintf(LOG_PHASE, "HDLC errros -> FCS: %u ADDR: %u COMD: %u PROTO: %u\n",
+ hp->badfcs - op->badfcs, hp->badaddr - op->badaddr,
+ hp->badcommand - op->badcommand, hp->unknownproto - op->unknownproto);
+ }
+ laststat = HdlcStat;
+}
+
+void
+HdlcInput(struct mbuf *bp)
+{
+ u_short fcs, proto;
+ u_char *cp, addr, ctrl;
+ struct protostat *statp;
+
+ LogDumpBp(LOG_HDLC, "HdlcInput:", bp);
+ fcs = HdlcFcs(INITFCS, MBUF_CTOP(bp), bp->cnt);
+ HisLqrSave.SaveInOctets += bp->cnt + 1;
+
+#ifdef DEBUG
+ logprintf("fcs = %04x (%s)\n", fcs, (fcs == GOODFCS)? "good" : "bad");
+#endif
+ if (fcs != GOODFCS) {
+ HisLqrSave.SaveInErrors++;
+#ifdef DEBUG
+ logprintf("Bad FCS\n");
+#endif
+ HdlcStat.badfcs++;
+ pfree(bp);
+ return;
+ }
+ bp->cnt -= 2; /* discard FCS part */
+ cp = MBUF_CTOP(bp);
+
+ ifInPackets++;
+ ifInOctets += bp->cnt;
+
+ if (!LcpInfo.want_acfcomp) {
+ /*
+ * We expect that packet is not compressed.
+ */
+ addr = *cp++;
+ if (addr != HDLC_ADDR) {
+ HisLqrSave.SaveInErrors++;
+ HdlcStat.badaddr++;
+#ifdef DEBUG
+ logprintf("addr %02x\n", *cp);
+#endif
+ pfree(bp);
+ return;
+ }
+
+ ctrl = *cp++;
+ if (ctrl != HDLC_UI) {
+ HisLqrSave.SaveInErrors++;
+ HdlcStat.badcommand++;
+#ifdef DEBUG
+ logprintf("command %02x\n", *cp);
+#endif
+ pfree(bp);
+ return;
+ }
+ bp->offset += 2;
+ bp->cnt -= 2;
+ } else if (cp[0] == HDLC_ADDR && cp[1] == HDLC_UI) {
+ /*
+ * We can receive compressed packet, but peer still send
+ * uncompressed packet to me.
+ */
+ cp += 2;
+ bp->offset += 2;
+ bp->cnt -= 2;
+ }
+
+ if (LcpInfo.want_protocomp) {
+ proto = 0;
+ cp--;
+ do {
+ cp++; bp->offset++; bp->cnt--;
+ proto = proto << 8;
+ proto += *cp;
+ } while (!(proto & 1));
+ } else {
+ proto = *cp++ << 8;
+ proto |= *cp++;
+ bp->offset += 2;
+ bp->cnt -= 2;
+ }
+
+ for (statp = ProtocolStat; statp->number; statp++)
+ if (statp->number == proto)
+ break;
+ statp->in_count++;
+ HisLqrSave.SaveInPackets++;
+
+ DecodePacket(proto, bp);
+}
diff --git a/usr.sbin/ppp/hdlc.h b/usr.sbin/ppp/hdlc.h
new file mode 100644
index 0000000..3c03655
--- /dev/null
+++ b/usr.sbin/ppp/hdlc.h
@@ -0,0 +1,58 @@
+/*
+ * 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. 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:
+ */
+
+#ifndef _HDLC_H_
+#define _HDLC_H_
+
+/*
+ * Definition for Async HDLC
+ */
+#define HDLC_SYN 0x7e /* SYNC character */
+#define HDLC_ESC 0x7d /* Escape character */
+#define HDLC_XOR 0x20 /* Modifier value */
+
+#define HDLC_ADDR 0xff
+#define HDLC_UI 0x03
+/*
+ * Definition for HDLC Frame Check Sequence
+ */
+#define INITFCS 0xffff /* Initial value for FCS computation */
+#define GOODFCS 0xf0b8 /* Good FCS value */
+
+#define DEF_MRU 1500
+#define MAX_MRU 2000
+#define MIN_MRU 296
+
+/*
+ * Output priority
+ */
+#define PRI_NORMAL 0 /* Normal priority */
+#define PRI_FAST 1 /* Fast (interructive) */
+#define PRI_URGENT 2 /* Urgent (LQR packets) */
+
+unsigned char EscMap[33];
+
+void HdlcInput(struct mbuf *bp);
+void HdlcOutput(int pri, u_short proto, struct mbuf *bp);
+void AsyncOutput(int pri, struct mbuf *bp, int proto);
+
+#endif
diff --git a/usr.sbin/ppp/ip.c b/usr.sbin/ppp/ip.c
new file mode 100644
index 0000000..23fd550
--- /dev/null
+++ b/usr.sbin/ppp/ip.c
@@ -0,0 +1,398 @@
+/*
+ * PPP IP Protocol Interface
+ *
+ * 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. 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 Return ICMP message for filterd packet
+ * and optionaly record it into log.
+ */
+#include "fsm.h"
+#include "lcpproto.h"
+#include "hdlc.h"
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/udp.h>
+#include <netinet/tcp.h>
+#include "vars.h"
+#include "filter.h"
+
+extern void SendPppFlame();
+extern int PacketCheck();
+extern void LcpClose();
+
+static struct pppTimer IdleTimer;
+
+static void IdleTimeout()
+{
+ LogPrintf(LOG_PHASE, "Idle timer expired.\n");
+ LcpClose();
+}
+
+/*
+ * Start Idle timer. If timeout is reached, we call LcpClose() to
+ * close LCP and link.
+ */
+void
+StartIdleTimer()
+{
+ if (!(mode & MODE_DEDICATED)) {
+ StopTimer(&IdleTimer);
+ IdleTimer.func = IdleTimeout;
+ IdleTimer.load = VarIdleTimeout * SECTICKS;
+ IdleTimer.state = TIMER_STOPPED;
+ StartTimer(&IdleTimer);
+ }
+}
+
+void
+StopIdleTimer()
+{
+ StopTimer(&IdleTimer);
+}
+
+/*
+ * If any IP layer traffic is detected, refresh IdleTimer.
+ */
+static void
+RestartIdleTimer()
+{
+ if (!(mode & MODE_DEDICATED)) {
+ StopTimer(&IdleTimer);
+ StartTimer(&IdleTimer);
+ ipIdleSecs = 0;
+ }
+}
+
+static u_short interactive_ports[8] = {
+ 0, 513, 0, 0, 0, 21, 0, 23,
+};
+
+#define INTERACTIVE(p) (interactive_ports[(p) & 7] == (p))
+
+static char *TcpFlags[] = {
+ "FIN", "SYN", "RST", "PSH", "ACK", "URG",
+};
+
+static char *Direction[] = { "INP", "OUT", "OUT" };
+static struct filterent *Filters[] = { ifilters, ofilters, dfilters };
+
+static int
+PortMatch(op, pport, rport)
+int op;
+u_short pport, rport;
+{
+ switch (op) {
+ case OP_EQ:
+ return(pport == rport);
+ case OP_GT:
+ return(pport > rport);
+ case OP_LT:
+ return(pport < rport);
+ default:
+ return(0);
+ }
+}
+
+/*
+ * Check a packet against with defined filters
+ */
+static int
+FilterCheck(pip, direction)
+struct ip *pip;
+int direction;
+{
+ struct filterent *fp = Filters[direction];
+ int gotinfo, cproto, estab, n;
+ struct tcphdr *th;
+ struct udphdr *uh;
+ struct icmp *ih;
+ char *ptop;
+ u_short sport, dport;
+
+ if (fp->action) {
+ cproto = gotinfo = estab = 0;
+ sport = dport = 0;
+ for (n = 0; n < MAXFILTERS; n++) {
+ if (fp->action) {
+#ifdef DEBUG
+logprintf("rule = %d\n", n);
+#endif
+ if ((pip->ip_src.s_addr & fp->smask.s_addr) == fp->saddr.s_addr
+ && (pip->ip_dst.s_addr & fp->dmask.s_addr) == fp->daddr.s_addr) {
+ if (fp->proto) {
+ if (!gotinfo) {
+ ptop = (char *)pip + (pip->ip_hl << 2);
+
+ switch (pip->ip_p) {
+ case IPPROTO_ICMP:
+ cproto = P_ICMP; ih = (struct icmp *)ptop;
+ sport = ih->icmp_type; estab = 1;
+ break;
+ case IPPROTO_UDP:
+ cproto = P_UDP; uh = (struct udphdr *)ptop;
+ sport = ntohs(uh->uh_sport); dport = ntohs(uh->uh_dport);
+ estab = 1;
+ break;
+ case IPPROTO_TCP:
+ cproto = P_TCP; th = (struct tcphdr *)ptop;
+ sport = ntohs(th->th_sport); dport = ntohs(th->th_dport);
+ estab = (th->th_flags & TH_ACK);
+ break;
+ default:
+ return(A_DENY); /* We'll block unknown type of packet */
+ }
+ gotinfo = 1;
+#ifdef DEBUG
+logprintf("dir = %d, proto = %d, srcop = %d, dstop = %d, estab = %d\n",
+direction, cproto, fp->opt.srcop, fp->opt.dstop, estab);
+if (estab == 0)
+logprintf("flag = %02x, sport = %d, dport = %d\n", th->th_flags, sport, dport);
+#endif
+ }
+#ifdef DEBUG
+ logprintf("check0: rule = %d, proto = %d, sport = %d, dport = %d\n",
+ n, cproto, sport, dport);
+ logprintf("check0: action = %d\n", fp->action);
+#endif
+ if (cproto == fp->proto) {
+ if ((fp->opt.srcop == OP_NONE ||
+ PortMatch(fp->opt.srcop, sport, fp->opt.srcport))
+ &&
+ (fp->opt.dstop == OP_NONE ||
+ PortMatch(fp->opt.dstop, dport, fp->opt.dstport))
+ &&
+ (fp->opt.estab == 0 || estab)) {
+ return(fp->action);
+ }
+ }
+ } else {
+ /* Address is mached. Make a decision. */
+#ifdef DEBUG
+ logprintf("check1: action = %d\n", fp->action);
+#endif
+ return(fp->action);
+ }
+ }
+ }
+ fp++;
+ }
+drop:
+ return(A_DENY); /* No rule is mached. Deny this packet */
+ }
+ return(A_PERMIT); /* No rule is given. Permit this packet */
+}
+
+static void
+IcmpError(pip, code)
+struct ip *pip;
+int code;
+{
+#ifdef notdef
+ struct mbuf *bp;
+
+ if (pip->ip_p != IPPROTO_ICMP) {
+ bp = mballoc(cnt, MB_IPIN);
+ bcopy(ptr, MBUF_CTOP(bp), cnt);
+ SendPppFlame(PRI_URGENT, bp);
+ RestartIdleTimer();
+ ipOutOctets += cnt;
+ }
+#endif
+}
+
+/*
+ * For debugging aid.
+ */
+int
+PacketCheck(cp, nb, direction)
+char *cp;
+int nb;
+int direction;
+{
+ struct ip *pip;
+ struct tcphdr *th;
+ struct udphdr *uh;
+ struct icmp *icmph;
+ char *ptop;
+ int mask, len, n;
+ int logit;
+ int pri = PRI_NORMAL;
+
+ logit = (loglevel & (1 << LOG_TCPIP));
+
+ pip = (struct ip *)cp;
+
+ if (logit) logprintf("%s ", Direction[direction]);
+
+ ptop = (cp + (pip->ip_hl << 2));
+
+ switch (pip->ip_p) {
+ case IPPROTO_ICMP:
+ if (logit) {
+ icmph = (struct icmp *)ptop;
+ logprintf("ICMP: %s:%d ---> ", inet_ntoa(pip->ip_src), icmph->icmp_type);
+ logprintf("%s:%d\n", inet_ntoa(pip->ip_dst), icmph->icmp_type);
+ }
+ break;
+ case IPPROTO_UDP:
+ if (logit) {
+ uh = (struct udphdr *)ptop;
+ logprintf("UDP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
+ logprintf("%s:%d\n", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
+ }
+ break;
+ case IPPROTO_TCP:
+ th = (struct tcphdr *)ptop;
+ if (pip->ip_tos == IPTOS_LOWDELAY)
+ pri = PRI_FAST;
+ else if (pip->ip_off == 0) {
+ if (INTERACTIVE(ntohs(th->th_sport)) || INTERACTIVE(ntohs(th->th_dport)))
+ pri = PRI_FAST;
+ }
+
+ if (logit) {
+ len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - (th->th_off << 2);
+ logprintf("TCP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(th->th_sport));
+ logprintf("%s:%d", inet_ntoa(pip->ip_dst), ntohs(th->th_dport));
+ n = 0;
+ for (mask = TH_FIN; mask != 0x40; mask <<= 1) {
+ if (th->th_flags & mask)
+ logprintf(" %s", TcpFlags[n]);
+ n++;
+ }
+ logprintf(" seq:%x ack:%x (%d/%d)\n",
+ ntohl(th->th_seq), ntohl(th->th_ack), len, nb);
+ if ((th->th_flags & TH_SYN) && nb > 40) {
+ u_short *sp;
+
+ ptop += 20;
+ sp = (u_short *)ptop;
+ if (ntohs(sp[0]) == 0x0204)
+ logprintf(" MSS = %d\n", ntohs(sp[1]));
+ }
+ }
+ break;
+ }
+ pri = FilterCheck(pip, direction);
+ if (pri & A_DENY) {
+#ifdef DEBUG
+ logprintf("blocked.\n");
+#endif
+ if (direction == 0) IcmpError(pip, pri);
+ return(-1);
+ } else {
+ return(pri);
+ }
+}
+
+void
+IpInput(bp)
+struct mbuf *bp; /* IN: Pointer to IP pakcet */
+{
+ u_char *cp;
+ struct mbuf *wp;
+ int nb, nw;
+ u_char tunbuff[MAX_MRU];
+
+ cp = tunbuff;
+ nb = 0;
+ for (wp = bp; wp; wp = wp->next) { /* Copy to continuois region */
+ bcopy(MBUF_CTOP(wp), cp, wp->cnt);
+ cp += wp->cnt;
+ nb += wp->cnt;
+ }
+
+ if (PacketCheck(tunbuff, nb, 0) < 0) {
+ pfree(bp);
+ return;
+ }
+
+ ipInOctets += nb;
+ /*
+ * Pass it to tunnel device
+ */
+ nw = write(tun_out, tunbuff, nb);
+ if (nw != nb)
+ fprintf(stderr, "wrote %d, got %d\r\n");
+ pfree(bp);
+
+ RestartIdleTimer();
+}
+
+void
+IpOutput(ptr, cnt)
+u_char *ptr; /* IN: Pointer to IP packet */
+int cnt; /* IN: Length of packet */
+{
+ struct mbuf *bp;
+ int pri;
+
+ if (IpcpFsm.state != ST_OPENED)
+ return;
+
+ pri = PacketCheck(ptr, cnt, 1);
+ if (pri >= 0) {
+ bp = mballoc(cnt, MB_IPIN);
+ bcopy(ptr, MBUF_CTOP(bp), cnt);
+ SendPppFlame(pri, bp);
+ RestartIdleTimer();
+ ipOutOctets += cnt;
+ }
+}
+
+static struct mqueue IpOutputQueues[PRI_URGENT+1];
+
+void
+IpEnqueue(pri, ptr, count)
+int pri;
+char *ptr;
+int count;
+{
+ struct mbuf *bp;
+
+ bp = mballoc(count, MB_IPQ);
+ bcopy(ptr, MBUF_CTOP(bp), count);
+ Enqueue(&IpOutputQueues[pri], bp);
+}
+
+void
+IpStartOutput()
+{
+ struct mqueue *queue;
+ struct mbuf *bp;
+ int pri, cnt;
+
+ if (IpcpFsm.state != ST_OPENED)
+ return;
+ pri = PRI_URGENT;
+ for (queue = &IpOutputQueues[PRI_URGENT]; queue >= IpOutputQueues; queue--) {
+ if (queue->top) {
+ bp = Dequeue(queue);
+ if (bp) {
+ cnt = plength(bp);
+ SendPppFlame(pri, bp);
+ RestartIdleTimer();
+ ipOutOctets += cnt;
+ }
+ }
+ pri--;
+ }
+}
diff --git a/usr.sbin/ppp/ipcp.c b/usr.sbin/ppp/ipcp.c
new file mode 100644
index 0000000..02187f3
--- /dev/null
+++ b/usr.sbin/ppp/ipcp.c
@@ -0,0 +1,459 @@
+/*
+ * PPP IP Control Protocol (IPCP) 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 More RFC1772 backwoard compatibility
+ */
+#include "fsm.h"
+#include "lcpproto.h"
+#include "lcp.h"
+#include "ipcp.h"
+#include <netdb.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include "slcompress.h"
+#include "os.h"
+#include "phase.h"
+#include "vars.h"
+
+extern void PutConfValue();
+extern void Prompt();
+extern struct in_addr ifnetmask;
+
+struct ipcpstate IpcpInfo;
+struct in_range DefMyAddress, DefHisAddress;
+
+static void IpcpSendConfigReq(struct fsm *);
+static void IpcpSendTerminateAck(struct fsm *);
+static void IpcpSendTerminateReq(struct fsm *);
+static void IpcpDecodeConfig();
+static void IpcpLayerStart(struct fsm *);
+static void IpcpLayerFinish(struct fsm *);
+static void IpcpLayerUp(struct fsm *);
+static void IpcpLayerDown(struct fsm *);
+static void IpcpInitRestartCounter(struct fsm *);
+
+static struct pppTimer IpcpReportTimer;
+
+static int lastInOctets, lastOutOctets;
+
+#define REJECTED(p, x) (p->his_reject & (1<<x))
+
+struct fsm IpcpFsm = {
+ "IPCP",
+ PROTO_IPCP,
+ IPCP_MAXCODE,
+ OPEN_ACTIVE,
+ ST_INITIAL,
+ 0, 0, 0,
+
+ 0,
+ { 0, 0, 0, NULL, NULL, NULL },
+
+ IpcpLayerUp,
+ IpcpLayerDown,
+ IpcpLayerStart,
+ IpcpLayerFinish,
+ IpcpInitRestartCounter,
+ IpcpSendConfigReq,
+ IpcpSendTerminateReq,
+ IpcpSendTerminateAck,
+ IpcpDecodeConfig,
+};
+
+static char *cftypes[] = {
+ "???", "IPADDRS", "COMPPROTO", "IPADDR",
+};
+
+/*
+ * Function called every second. Updates connection period and idle period,
+ * also update LQR information.
+ */
+static void
+IpcpReportFunc()
+{
+ ipConnectSecs++;
+ if (lastInOctets == ipInOctets && lastOutOctets == ipOutOctets)
+ ipIdleSecs++;
+ lastInOctets = ipInOctets;
+ lastOutOctets = ipOutOctets;
+ StopTimer(&IpcpReportTimer);
+ IpcpReportTimer.state = TIMER_STOPPED;
+ StartTimer(&IpcpReportTimer);
+}
+
+static void
+IpcpStartReport()
+{
+ ipIdleSecs = ipConnectSecs = 0;
+ StopTimer(&IpcpReportTimer);
+ IpcpReportTimer.state = TIMER_STOPPED;
+ IpcpReportTimer.load = SECTICKS;
+ IpcpReportTimer.func = IpcpReportFunc;
+ StartTimer(&IpcpReportTimer);
+}
+
+void
+ReportIpcpStatus()
+{
+ struct ipcpstate *icp = &IpcpInfo;
+ struct fsm *fp = &IpcpFsm;
+
+ printf("%s [%s]\n", fp->name, StateNames[fp->state]);
+ printf(" his side: %s, %x\n",
+ inet_ntoa(icp->his_ipaddr), icp->his_compproto);
+ printf(" my side: %s, %x\n",
+ inet_ntoa(icp->want_ipaddr), icp->want_compproto);
+ printf("connected: %d secs, idle: %d secs\n\n", ipConnectSecs, ipIdleSecs);
+ printf("Defaults: My Address: %s/%d ",
+ inet_ntoa(DefMyAddress.ipaddr), DefMyAddress.width);
+ printf("His Address: %s/%d\n",
+ inet_ntoa(DefHisAddress.ipaddr), DefHisAddress.width);
+}
+
+void
+IpcpDefAddress()
+{
+ struct hostent *hp;
+ char name[200];
+
+ bzero(&DefMyAddress, sizeof(DefMyAddress));
+ bzero(&DefHisAddress, sizeof(DefHisAddress));
+ if (gethostname(name, sizeof(name)) == 0) {
+ hp = gethostbyname(name);
+ if (hp && hp->h_addrtype == AF_INET) {
+ bcopy(hp->h_addr, (char *)&DefMyAddress.ipaddr.s_addr, hp->h_length);
+ }
+ }
+}
+
+void
+IpcpInit()
+{
+ struct ipcpstate *icp = &IpcpInfo;
+
+ FsmInit(&IpcpFsm);
+ bzero(icp, sizeof(struct ipcpstate));
+ if ((mode & MODE_DEDICATED) && !dstsystem) {
+ icp->want_ipaddr.s_addr = icp->his_ipaddr.s_addr = 0;
+ } else {
+ icp->want_ipaddr.s_addr = DefMyAddress.ipaddr.s_addr;
+ icp->his_ipaddr.s_addr = DefHisAddress.ipaddr.s_addr;
+ }
+ if (icp->want_ipaddr.s_addr == 0)
+ icp->want_ipaddr.s_addr = htonl(0xc0000001);
+ if (Enabled(ConfVjcomp))
+ icp->want_compproto = (PROTO_VJCOMP << 16) | ((MAX_STATES - 1) << 8);
+ else
+ icp->want_compproto = 0;
+ icp->heis1172 = 0;
+ IpcpFsm.maxconfig = 10;
+}
+
+static void
+IpcpInitRestartCounter(fp)
+struct fsm *fp;
+{
+ fp->FsmTimer.load = 3 * SECTICKS;
+ fp->restart = 5;
+}
+
+static void
+IpcpSendConfigReq(fp)
+struct fsm *fp;
+{
+ u_char *cp;
+ struct ipcpstate *icp = &IpcpInfo;
+
+ cp = ReqBuff;
+ LogPrintf(LOG_LCP, "%s: SendConfigReq\n", fp->name);
+ PutConfValue(&cp, cftypes, TY_IPADDR, 6, ntohl(icp->want_ipaddr.s_addr));
+ if (icp->want_compproto && !REJECTED(icp, TY_COMPPROTO)) {
+ if (icp->heis1172)
+ PutConfValue(&cp, cftypes, TY_COMPPROTO, 4, icp->want_compproto >> 16);
+ else
+ PutConfValue(&cp, cftypes, TY_COMPPROTO, 6, icp->want_compproto);
+ }
+ FsmOutput(fp, CODE_CONFIGREQ, fp->reqid++, ReqBuff, cp - ReqBuff);
+}
+
+static void
+IpcpSendTerminateReq(fp)
+struct fsm *fp;
+{
+ /* XXX: No code yet */
+}
+
+static void
+IpcpSendTerminateAck(fp)
+struct fsm *fp;
+{
+ LogPrintf(LOG_LCP, " %s: SendTerminateAck\n", fp->name);
+ FsmOutput(fp, CODE_TERMACK, fp->reqid++, NULL, 0);
+}
+
+static void
+IpcpLayerStart(fp)
+struct fsm *fp;
+{
+ LogPrintf(LOG_LCP, "%s: LayerStart.\n", fp->name);
+}
+
+static void
+IpcpLayerFinish(fp)
+struct fsm *fp;
+{
+ LogPrintf(LOG_LCP, "%s: LayerFinish.\n", fp->name);
+ LcpClose();
+ NewPhase(PHASE_TERMINATE);
+}
+
+static void
+IpcpLayerDown(fp)
+struct fsm *fp;
+{
+ LogPrintf(LOG_LCP, "%s: LayerDown.\n", fp->name);
+ StopTimer(&IpcpReportTimer);
+}
+
+/*
+ * Called when IPCP has reached to OPEN state
+ */
+static void
+IpcpLayerUp(fp)
+struct fsm *fp;
+{
+ char tbuff[100];
+
+#ifdef VERBOSE
+ fprintf(stderr, "%s: LayerUp(%d).\r\n", fp->name, fp->state);
+#endif
+ Prompt(1);
+ LogPrintf(LOG_LCP, "%s: LayerUp.\n", fp->name);
+ sprintf(tbuff, "myaddr = %s ", inet_ntoa(IpcpInfo.want_ipaddr));
+ LogPrintf(LOG_LCP, " %s hisaddr = %s\n", tbuff, inet_ntoa(IpcpInfo.his_ipaddr));
+ OsSetIpaddress(IpcpInfo.want_ipaddr, IpcpInfo.his_ipaddr, ifnetmask);
+ OsLinkup();
+ IpcpStartReport();
+ StartIdleTimer();
+}
+
+void
+IpcpUp()
+{
+ FsmUp(&IpcpFsm);
+ LogPrintf(LOG_LCP, "IPCP Up event!!\n");
+}
+
+void
+IpcpOpen()
+{
+ FsmOpen(&IpcpFsm);
+}
+
+static int
+AcceptableAddr(prange, ipaddr)
+struct in_range *prange;
+struct in_addr ipaddr;
+{
+#ifdef DEBUG
+ logprintf("requested = %x ", htonl(ipaddr.s_addr));
+ logprintf("range = %x", htonl(prange->ipaddr.s_addr));
+ logprintf("/%x\n", htonl(prange->mask.s_addr));
+ logprintf("%x, %x\n", htonl(prange->ipaddr.s_addr & prange->mask.s_addr),
+ htonl(ipaddr.s_addr & prange->mask.s_addr));
+#endif
+ return((prange->ipaddr.s_addr & prange->mask.s_addr) ==
+ (ipaddr.s_addr & prange->mask.s_addr));
+}
+
+static void
+IpcpDecodeConfig(bp, mode)
+struct mbuf *bp;
+int mode;
+{
+ u_char *cp;
+ int plen, type, length;
+ u_long *lp, compproto;
+ struct compreq *pcomp;
+ struct in_addr ipaddr, dstipaddr;
+ char tbuff[100];
+
+ plen = plength(bp);
+
+ cp = MBUF_CTOP(bp);
+ ackp = AckBuff;
+ nakp = NakBuff;
+ rejp = RejBuff;
+
+ while (plen >= sizeof(struct fsmconfig)) {
+ if (plen < 0)
+ break;
+ type = *cp;
+ length = cp[1];
+ if (type <= TY_IPADDR)
+ sprintf(tbuff, " %s[%d] ", cftypes[type], length);
+ else
+ sprintf(tbuff, " ");
+
+ switch (type) {
+ case TY_IPADDR: /* RFC1332 */
+ lp = (u_long *)(cp + 2);
+ ipaddr.s_addr = *lp;
+ LogPrintf(LOG_LCP, "%s %s\n", tbuff, inet_ntoa(ipaddr));
+
+ switch (mode) {
+ case MODE_REQ:
+ if (!AcceptableAddr(&DefHisAddress, ipaddr)) {
+ /*
+ * If destination address is not acceptable, insist to use
+ * what we want to use.
+ */
+ bcopy(cp, nakp, 2);
+ bcopy(&IpcpInfo.his_ipaddr.s_addr, nakp+2, length);
+ nakp += length;
+ break;
+
+ }
+ IpcpInfo.his_ipaddr = ipaddr;
+ bcopy(cp, ackp, length);
+ ackp += length;
+ break;
+ case MODE_NAK:
+ if (AcceptableAddr(&DefMyAddress, ipaddr)) {
+ /*
+ * Use address suggested by peer.
+ */
+ sprintf(tbuff+50, "%s changing address: %s ", tbuff, inet_ntoa(IpcpInfo.want_ipaddr));
+ LogPrintf(LOG_LCP, "%s --> %s\n", tbuff+50, inet_ntoa(ipaddr));
+ IpcpInfo.want_ipaddr = ipaddr;
+ }
+ break;
+ case MODE_REJ:
+ IpcpInfo.his_reject |= (1 << type);
+ break;
+ }
+ break;
+ case TY_COMPPROTO:
+ lp = (u_long *)(cp + 2);
+ compproto = htonl(*lp);
+ LogPrintf(LOG_LCP, "%s %08x\n", tbuff, compproto);
+
+ switch (mode) {
+ case MODE_REQ:
+ if (!Acceptable(ConfVjcomp)) {
+ bcopy(cp, rejp, length);
+ rejp += length;
+ } else {
+ pcomp = (struct compreq *)(cp + 2);
+ switch (length) {
+ case 4: /* RFC1172 */
+ if (ntohs(pcomp->proto) == PROTO_VJCOMP) {
+ logprintf("** Peer is speaking RFC1172 compression protocol **\n");
+ IpcpInfo.heis1172 = 1;
+ IpcpInfo.his_compproto = compproto;
+ bcopy(cp, ackp, length);
+ ackp += length;
+ } else {
+ bcopy(cp, nakp, 2);
+ pcomp->proto = htons(PROTO_VJCOMP);
+ bcopy(&pcomp, nakp + 2, 2);
+ nakp += length;
+ }
+ break;
+ case 6: /* RFC1332 */
+ if (ntohs(pcomp->proto) == PROTO_VJCOMP
+ && pcomp->slots < MAX_STATES && pcomp->slots > 2) {
+ IpcpInfo.his_compproto = compproto;
+ IpcpInfo.heis1172 = 0;
+ bcopy(cp, ackp, length);
+ ackp += length;
+ } else {
+ bcopy(cp, nakp, 2);
+ pcomp->proto = htons(PROTO_VJCOMP);
+ pcomp->slots = MAX_STATES - 1;
+ pcomp->compcid = 0;
+ bcopy(&pcomp, nakp + 2, sizeof(pcomp));
+ nakp += length;
+ }
+ break;
+ default:
+ bcopy(cp, rejp, length);
+ rejp += length;
+ break;
+ }
+ }
+ break;
+ case MODE_NAK:
+ LogPrintf(LOG_LCP, "%s changing compproto: %08x --> %08x\n",
+ tbuff, IpcpInfo.want_compproto, compproto);
+ IpcpInfo.want_compproto = compproto;
+ break;
+ case MODE_REJ:
+ IpcpInfo.his_reject |= (1 << type);
+ break;
+ }
+ break;
+ case TY_IPADDRS: /* RFC1172 */
+ lp = (u_long *)(cp + 2);
+ ipaddr.s_addr = *lp;
+ lp = (u_long *)(cp + 6);
+ dstipaddr.s_addr = *lp;
+ LogPrintf(LOG_LCP, "%s %s, ", tbuff, inet_ntoa(ipaddr));
+ LogPrintf(LOG_LCP, "%s\n", inet_ntoa(dstipaddr));
+
+ switch (mode) {
+ case MODE_REQ:
+ IpcpInfo.his_ipaddr = ipaddr;
+ IpcpInfo.want_ipaddr = dstipaddr;
+ bcopy(cp, ackp, length);
+ ackp += length;
+ break;
+ case MODE_NAK:
+ LogPrintf(LOG_LCP, "%s changing address: %s ",
+ tbuff, inet_ntoa(IpcpInfo.want_ipaddr));
+ LogPrintf(LOG_LCP, "--> %s\n", inet_ntoa(ipaddr));
+ IpcpInfo.want_ipaddr = ipaddr;
+ IpcpInfo.his_ipaddr = dstipaddr;
+ break;
+ case MODE_REJ:
+ IpcpInfo.his_reject |= (1 << type);
+ break;
+ }
+ break;
+ default:
+ IpcpInfo.my_reject |= (1 << type);
+ bcopy(cp, rejp, length);
+ rejp += length;
+ break;
+ }
+ plen -= length;
+ cp += length;
+ }
+}
+
+void
+IpcpInput(struct mbuf *bp)
+{
+ FsmInput(&IpcpFsm, bp);
+}
diff --git a/usr.sbin/ppp/ipcp.h b/usr.sbin/ppp/ipcp.h
new file mode 100644
index 0000000..a90c83a
--- /dev/null
+++ b/usr.sbin/ppp/ipcp.h
@@ -0,0 +1,62 @@
+/*
+ * 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. 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:
+ */
+
+#ifndef _IPCP_H_
+#define _IPCP_H_
+
+#define IPCP_MAXCODE CODE_CODEREJ
+
+#define TY_IPADDRS 1
+#define TY_COMPPROTO 2
+#define TY_IPADDR 3
+
+struct ipcpstate {
+ struct in_addr his_ipaddr; /* IP address he is willing to use */
+ u_long his_compproto;
+
+ struct in_addr want_ipaddr; /* IP address I'm willing to use */
+ u_long want_compproto;
+
+ u_long his_reject; /* Request codes rejected by peer */
+ u_long my_reject; /* Request codes I have rejected */
+ int heis1172; /* True if he is speaking rfc1172 */
+};
+
+struct compreq {
+ u_short proto;
+ u_char slots;
+ u_char compcid;
+};
+
+struct in_range {
+ struct in_addr ipaddr;
+ struct in_addr mask;
+ int width;
+};
+
+extern struct ipcpstate IpcpInfo;
+extern struct in_range DefMyAddress;
+extern struct in_range DefHisAddress;
+
+extern void IpcpInit(void);
+extern void IpcpDefAddress();
+#endif
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);
+}
diff --git a/usr.sbin/ppp/lcp.h b/usr.sbin/ppp/lcp.h
new file mode 100644
index 0000000..2fb2e32
--- /dev/null
+++ b/usr.sbin/ppp/lcp.h
@@ -0,0 +1,83 @@
+/*
+ * 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. 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:
+ */
+
+#ifndef _LCP_H_
+#define _LPC_H_
+
+struct lcpstate {
+ u_long his_mru;
+ u_long his_accmap;
+ u_long his_magic;
+ u_long his_lqrperiod;
+ u_char his_protocomp;
+ u_char his_acfcomp;
+ u_short his_auth;
+
+ u_long want_mru;
+ u_long want_accmap;
+ u_long want_magic;
+ u_long want_lqrperiod;
+ u_char want_protocomp;
+ u_char want_acfcomp;
+ u_short want_auth;
+
+ u_long his_reject; /* Request codes rejected by peer */
+ u_long my_reject; /* Request codes I have rejected */
+
+ u_short auth_iwait;
+ u_short auth_ineed;
+};
+
+#define LCP_MAXCODE CODE_DISCREQ
+
+#define TY_MRU 1 /* Maximum-Receive-Unit */
+#define TY_ACCMAP 2 /* Async-Control-Character-Map */
+#define TY_AUTHPROTO 3 /* Authentication-Protocol */
+#define TY_QUALPROTO 4 /* Quality-Protocol */
+#define TY_MAGICNUM 5 /* Magic-Number */
+#define TY_RESERVED 6 /* RESERVED */
+#define TY_PROTOCOMP 7 /* Protocol-Field-Compression */
+#define TY_ACFCOMP 8 /* Address-and-Control-Field-Compression */
+#define TY_FCSALT 9 /* FCS-Alternatives */
+#define TY_SDP 10 /* Self-Dscribing-Padding */
+#define TY_NUMMODE 11 /* Numbered-Mode */
+#define TY_XXXXXX 12
+#define TY_CALLBACK 13 /* Callback */
+#define TY_YYYYYY 14
+#define TY_COMPFRAME 15 /* Compound-Frames */
+
+struct lqrreq {
+ u_char type;
+ u_char length;
+ u_short proto; /* Quality protocol */
+ u_long period; /* Reporting interval */
+};
+
+extern struct lcpstate LcpInfo;
+
+extern void LcpInit(void);
+extern void LcpUp(void);
+extern void LcpSendProtoRej(u_char *, int);
+extern void LcpOpen(int mode);
+extern void LcpClose(void);
+extern void LcpDown(void);
+#endif
diff --git a/usr.sbin/ppp/lcpproto.h b/usr.sbin/ppp/lcpproto.h
new file mode 100644
index 0000000..2d1a974
--- /dev/null
+++ b/usr.sbin/ppp/lcpproto.h
@@ -0,0 +1,52 @@
+/*
+ * 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. 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:
+ */
+
+#ifndef _LCPPROTO_H_
+#define _LCPPROTO_H_
+
+/*
+ * Definition of protocol numbers
+ */
+#define PROTO_IP 0x0021 /* IP */
+#define PROTO_VJUNCOMP 0x002f /* VJ Uncompressed */
+#define PROTO_VJCOMP 0x002d /* VJ Compressed */
+#define PROTO_ICOMPD 0x00fb /* Individual link compressed */
+#define PROTO_COMPD 0x00fd /* Compressed datagram */
+
+#define PROTO_IPCP 0x8021
+#define PROTO_ICCP 0x80fb
+#define PROTO_CCP 0x80fd
+
+#define PROTO_LCP 0xc021
+#define PROTO_PAP 0xc023
+#define PROTO_LQR 0xc025
+#define PROTO_CHAP 0xc223
+
+extern void LcpInput(struct mbuf *bp);
+extern void PapInput(struct mbuf *bp);
+extern void LqpInput(struct mbuf *bp);
+extern void ChapInput(struct mbuf *bp);
+extern void IpInput(struct mbuf *bp);
+extern struct mbuf *VjCompInput(struct mbuf *bp, int proto);
+extern void IpcpInput(struct mbuf *bp);
+extern void LqrInput(struct mbuf *bp);
+#endif
diff --git a/usr.sbin/ppp/log.c b/usr.sbin/ppp/log.c
new file mode 100644
index 0000000..338cc3b
--- /dev/null
+++ b/usr.sbin/ppp/log.c
@@ -0,0 +1,223 @@
+/*
+ * PPP logging facility
+ *
+ * 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:
+ *
+ */
+#include "defs.h"
+#include <time.h>
+#include <netdb.h>
+
+#include "hdlc.h"
+
+#define MAXLOG 70
+
+#define USELOGFILE
+
+#ifdef USELOGFILE
+static FILE *logfile;
+#endif
+static char logbuff[2000];
+static char *logptr;
+static struct mbuf *logtop;
+static struct mbuf *lognext;
+static int logcnt;
+static int mypid;
+
+int loglevel = (1 << LOG_LCP)| (1 << LOG_PHASE);
+
+void
+ListLog()
+{
+ struct mbuf *bp;
+
+ for (bp = logtop; bp; bp = bp->next) {
+ write(1, MBUF_CTOP(bp), bp->cnt);
+ usleep(10);
+ }
+}
+
+int
+LogOpen()
+{
+#ifdef USELOGFILE
+ logfile = fopen(LOGFILE, "a");
+ if (logfile == NULL) {
+ fprintf(stderr, "can't open %s.\r\n", LOGFILE);
+ return(1);
+ }
+#endif
+ fprintf(stderr, "Log level is %02x\r\n", loglevel);
+ logptr = logbuff;
+ logcnt = 0;
+ logtop = lognext = NULL;
+ return(0);
+}
+
+void
+LogFlush()
+{
+ struct mbuf *bp;
+ int cnt;
+
+#ifdef USELOGFILE
+ *logptr = 0;
+ fprintf(logfile, "%s", logbuff);
+ fflush(logfile);
+#endif
+ cnt = logptr - logbuff + 1;
+ bp = mballoc(cnt, MB_LOG);
+ bcopy(logbuff, MBUF_CTOP(bp), cnt);
+ bp->cnt = cnt;
+ if (lognext) {
+ lognext->next = bp;
+ lognext = bp;
+ if (++logcnt > MAXLOG) {
+ logcnt--;
+ logtop = mbfree(logtop);
+ }
+ } else {
+ lognext = logtop = bp;
+ }
+ logptr = logbuff;
+}
+
+void
+DupLog()
+{
+ mypid = 0;
+#ifdef USELOGFILE
+ dup2(fileno(logfile), 2);
+#endif
+}
+
+void
+LogClose()
+{
+ LogFlush();
+#ifdef USELOGFILE
+ fclose(logfile);
+#endif
+}
+
+void
+logprintf(format, arg1, arg2, arg3, arg4, arg5, arg6)
+char *format;
+void *arg1, *arg2, *arg3, *arg4, *arg5, *arg6;
+{
+ sprintf(logptr, format, arg1, arg2, arg3, arg4, arg5, arg6);
+ logptr += strlen(logptr);
+ LogFlush();
+}
+
+void
+LogDumpBp(level, header, bp)
+int level;
+char *header;
+struct mbuf *bp;
+{
+ u_char *cp;
+ int cnt, loc;
+
+ if (!(loglevel & (1 << level)))
+ return;
+ LogTimeStamp();
+ sprintf(logptr, "%s\n", header);
+ logptr += strlen(logptr);
+ loc = 0;
+ LogTimeStamp();
+ while (bp) {
+ cp = MBUF_CTOP(bp);
+ cnt = bp->cnt;
+ while (cnt-- > 0) {
+ sprintf(logptr, " %02x", *cp++);
+ logptr += strlen(logptr);
+ if (++loc == 16) {
+ loc = 0;
+ *logptr++ = '\n';
+ if (logptr - logbuff > 1500)
+ LogFlush();
+ if (cnt) LogTimeStamp();
+ }
+ }
+ bp = bp->next;
+ }
+ if (loc) *logptr++ = '\n';
+ LogFlush();
+}
+
+void
+LogDumpBuff(level, header, ptr, cnt)
+int level;
+char *header;
+u_char *ptr;
+int cnt;
+{
+ int loc;
+
+ if (cnt < 1) return;
+ if (!(loglevel & (1 << level)))
+ return;
+ LogTimeStamp();
+ sprintf(logptr, "%s\n", header);
+ logptr += strlen(logptr);
+ LogTimeStamp();
+ loc = 0;
+ while (cnt-- > 0) {
+ sprintf(logptr, " %02x", *ptr++);
+ logptr += strlen(logptr);
+ if (++loc == 16) {
+ loc = 0;
+ *logptr++ = '\n';
+ if (cnt) LogTimeStamp();
+ }
+ }
+ if (loc) *logptr++ = '\n';
+ LogFlush();
+}
+
+void
+LogTimeStamp()
+{
+ struct tm *ptm;
+ time_t ltime;
+
+ if (mypid == 0)
+ mypid = getpid();
+ ltime = time(0);
+ ptm = localtime(&ltime);
+ sprintf(logptr, "%02d-%02d %02d:%02d:%02d [%d] ",
+ ptm->tm_mon + 1, ptm->tm_mday,
+ ptm->tm_hour, ptm->tm_min, ptm->tm_sec, mypid);
+ logptr += strlen(logptr);
+}
+
+void
+LogPrintf(level, format, arg1, arg2, arg3, arg4, arg5, arg6)
+int level;
+char *format;
+void *arg1, *arg2, *arg3, *arg4, *arg5, *arg6;
+{
+ if (!(loglevel & (1 << level)))
+ return;
+ LogTimeStamp();
+ logprintf(format, arg1, arg2, arg3, arg4, arg5, arg6);
+}
diff --git a/usr.sbin/ppp/log.h b/usr.sbin/ppp/log.h
new file mode 100644
index 0000000..34f21f7
--- /dev/null
+++ b/usr.sbin/ppp/log.h
@@ -0,0 +1,53 @@
+/*
+ * 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. 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:
+ */
+
+#ifndef _LOG_H_
+#define _LOG_H_
+/*
+ * Definition of log level
+ */
+#define LOG_PHASE 0
+# define LM_PHASE "Phase"
+#define LOG_CHAT 1
+# define LM_CHAT "Chat"
+#define LOG_LQM 2
+# define LM_LQM "LQM"
+#define LOG_LCP 3
+# define LM_LCP "LCP"
+#define LOG_TCPIP 4
+# define LM_TCPIP "TCP/IP"
+#define LOG_HDLC 5
+# define LM_HDLC "HDLC"
+#define LOG_ASYNC 6
+# define LM_ASYNC "Async"
+#define MAXLOGLEVEL 7
+
+extern int loglevel;
+
+extern void LogTimeStamp();
+extern int LogOpen();
+extern void DupLog();
+extern void LogClose();
+extern void logprintf(), LogPrintf();
+extern void LogDumpBp(int level, char *header, struct mbuf *bp);
+extern void LogDumpBuff(int level, char *header, u_char *ptr, int cnt);
+#endif
diff --git a/usr.sbin/ppp/lqr.c b/usr.sbin/ppp/lqr.c
new file mode 100644
index 0000000..c36fb21
--- /dev/null
+++ b/usr.sbin/ppp/lqr.c
@@ -0,0 +1,259 @@
+/*
+ * PPP Line Quality Monitoring (LQM) 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.
+ *
+ * o LQR based on RFC1333
+ *
+ * $Id:$
+ *
+ * TODO:
+ * o LQM policy
+ * o Allow user to configure LQM method and interval.
+ */
+#include "fsm.h"
+#include "lcpproto.h"
+#include "lqr.h"
+#include "hdlc.h"
+#include "lcp.h"
+#include "vars.h"
+
+struct pppTimer LqrTimer;
+
+static u_long lastpeerin = (u_long)-1;
+
+static int lqmmethod;
+static int echoseq;
+static int gotseq;
+static int lqrsendcnt;
+
+struct echolqr {
+ u_long magic;
+ u_long signature;
+ u_long sequence;
+};
+
+#define SIGNATURE 0x594e4f54
+
+static void
+SendEchoReq()
+{
+ struct fsm *fp = &LcpFsm;
+ struct echolqr *lqr, lqrdata;
+
+ if (fp->state == ST_OPENED) {
+ lqr = &lqrdata;
+ lqr->magic = htonl(LcpInfo.want_magic);
+ lqr->signature = htonl(SIGNATURE);
+ LogPrintf(LOG_LQM, "Send echo LQR [%d]\n", echoseq);
+ lqr->sequence = htonl(echoseq++);
+ FsmOutput(fp, CODE_ECHOREQ, fp->reqid++,
+ (u_char *)lqr, sizeof(struct echolqr));
+ }
+}
+
+void
+RecvEchoLqr(bp)
+struct mbuf *bp;
+{
+ struct echolqr *lqr;
+ u_long seq;
+
+ if (plength(bp) == sizeof(struct echolqr)) {
+ lqr = (struct echolqr *)MBUF_CTOP(bp);
+ if (htonl(lqr->signature) == SIGNATURE) {
+ seq = ntohl(lqr->sequence);
+ LogPrintf(LOG_LQM, "Got echo LQR [%d]\n", ntohl(lqr->sequence));
+ gotseq = seq;
+ }
+ }
+}
+
+void
+LqrChangeOrder(src, dst)
+struct lqrdata *src, *dst;
+{
+ u_long *sp, *dp;
+ int n;
+
+ sp = (u_long *)src; dp = (u_long *)dst;
+ for (n = 0; n < sizeof(struct lqrdata)/sizeof(u_long); n++)
+ *dp++ = ntohl(*sp++);
+}
+
+static void
+SendLqrReport()
+{
+ struct mbuf *bp;
+
+ StopTimer(&LqrTimer);
+
+ if (lqmmethod & LQM_LQR) {
+ if (lqrsendcnt > 5) {
+ /*
+ * XXX: Should implement LQM strategy
+ */
+ LogPrintf(LOG_PHASE, "** Too many ECHO packets are lost. **\n");
+ LcpClose();
+ Cleanup(EX_ERRDEAD);
+ } else {
+ bp = mballoc(sizeof(struct lqrdata), MB_LQR);
+ HdlcOutput(PRI_URGENT, PROTO_LQR, bp);
+ lqrsendcnt++;
+ }
+ } else if (lqmmethod & LQM_ECHO) {
+ if (echoseq - gotseq > 5) {
+ LogPrintf(LOG_PHASE, "** Too many ECHO packets are lost. **\n");
+ LcpClose();
+ Cleanup(EX_ERRDEAD);
+ } else
+ SendEchoReq();
+ }
+
+ if (lqmmethod && Enabled(ConfLqr))
+ StartTimer(&LqrTimer);
+}
+
+void
+LqrInput(struct mbuf *bp)
+{
+ int len;
+ u_char *cp;
+ struct lqrdata *lqr;
+
+ len = plength(bp);
+ if (len != sizeof(struct lqrdata)) {
+ pfree(bp);
+ return;
+ }
+
+ if (!Acceptable(ConfLqr)) {
+ bp->offset -= 2;
+ bp->cnt += 2;
+
+ cp = MBUF_CTOP(bp);
+ LcpSendProtoRej(cp, bp->cnt);
+ } else {
+ cp = MBUF_CTOP(bp);
+ lqr = (struct lqrdata *)cp;
+ if (ntohl(lqr->MagicNumber) != LcpInfo.his_magic) {
+#ifdef notdef
+logprintf("*** magic %x != expecting %x\n", ntohl(lqr->MagicNumber), LcpInfo.his_magic);
+#endif
+ pfree(bp);
+ return;
+ }
+
+ /*
+ * Convert byte order and save into our strage
+ */
+ LqrChangeOrder(lqr, &HisLqrData);
+ LqrDump("LqrInput", &HisLqrData);
+ lqrsendcnt = 0; /* we have received LQR from peer */
+
+ /*
+ * Generate LQR responce to peer, if
+ * i) We are not running LQR timer.
+ * ii) Two successive LQR's PeerInLQRs are same.
+ */
+ if (LqrTimer.load == 0 || lastpeerin == HisLqrData.PeerInLQRs) {
+ lqmmethod |= LQM_LQR;
+ SendLqrReport();
+ }
+ lastpeerin = HisLqrData.PeerInLQRs;
+ }
+ pfree(bp);
+}
+
+/*
+ * When LCP is reached to opened state, We'll start LQM activity.
+ */
+void
+StartLqm()
+{
+ struct lcpstate *lcp = &LcpInfo;
+ int period;
+
+ lqmmethod = LQM_ECHO;
+ if (Enabled(ConfLqr))
+ lqmmethod |= LQM_LQR;
+ StopTimer(&LqrTimer);
+ LogPrintf(LOG_LQM, "LQM method = %d\n", lqmmethod);
+
+ if (lcp->his_lqrperiod || lcp->want_lqrperiod) {
+ /*
+ * We need to run timer. Let's figure out period.
+ */
+ period = lcp->his_lqrperiod ? lcp->his_lqrperiod : lcp->want_lqrperiod;
+ StopTimer(&LqrTimer);
+ LqrTimer.state = TIMER_STOPPED;
+ LqrTimer.load = period * SECTICKS / 100;
+ LqrTimer.func = SendLqrReport;
+ SendLqrReport();
+ StartTimer(&LqrTimer);
+ LogPrintf(LOG_LQM, "Will send LQR every %d.%d secs\n",
+ period/100, period % 100);
+ } else {
+ LogPrintf(LOG_LQM, "LQR is not activated.\n");
+ }
+}
+
+void
+StopLqr(method)
+int method;
+{
+ LogPrintf(LOG_LQM, "StopLqr method = %x\n", method);
+
+ if (method == LQM_LQR)
+ LogPrintf(LOG_LQM, "Stop sending LQR, Use LCP ECHO instead.\n");
+ if (method == LQM_ECHO)
+ LogPrintf(LOG_LQM, "Stop sending LCP ECHO.\n");
+ lqmmethod &= ~method;
+ if (lqmmethod)
+ SendLqrReport();
+ else
+ StopTimer(&LqrTimer);
+}
+
+void
+LqrDump(message, lqr)
+char *message;
+struct lqrdata *lqr;
+{
+ if (loglevel >= LOG_LQM) {
+ LogTimeStamp();
+ logprintf("%s:\n", message);
+ LogTimeStamp();
+ logprintf(" Magic: %08x LastOutLQRs: %08x\n",
+ lqr->MagicNumber, lqr->LastOutLQRs);
+ LogTimeStamp();
+ logprintf(" LastOutPackets: %08x LastOutOctets: %08x\n",
+ lqr->LastOutPackets, lqr->LastOutOctets);
+ LogTimeStamp();
+ logprintf(" PeerInLQRs: %08x PeerInPackets: %08x\n",
+ lqr->PeerInLQRs, lqr->PeerInPackets);
+ LogTimeStamp();
+ logprintf(" PeerInDiscards: %08x PeerInErrors: %08x\n",
+ lqr->PeerInDiscards, lqr->PeerInErrors);
+ LogTimeStamp();
+ logprintf(" PeerInOctets: %08x PeerOutLQRs: %08x\n",
+ lqr->PeerInOctets, lqr->PeerOutLQRs);
+ LogTimeStamp();
+ logprintf(" PeerOutPackets: %08x PeerOutOctets: %08x\n",
+ lqr->PeerOutPackets, lqr->PeerOutOctets);
+ }
+}
diff --git a/usr.sbin/ppp/lqr.h b/usr.sbin/ppp/lqr.h
new file mode 100644
index 0000000..19c1392
--- /dev/null
+++ b/usr.sbin/ppp/lqr.h
@@ -0,0 +1,66 @@
+/*
+ * 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. 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:
+ */
+
+#ifndef _LQR_H_
+#define _LQR_H_
+
+/*
+ * Structure of LQR packet defined in RFC1333
+ */
+struct lqrdata {
+ u_long MagicNumber;
+ u_long LastOutLQRs;
+ u_long LastOutPackets;
+ u_long LastOutOctets;
+ u_long PeerInLQRs;
+ u_long PeerInPackets;
+ u_long PeerInDiscards;
+ u_long PeerInErrors;
+ u_long PeerInOctets;
+ u_long PeerOutLQRs;
+ u_long PeerOutPackets;
+ u_long PeerOutOctets;
+};
+
+struct lqrsave {
+ u_long SaveInLQRs;
+ u_long SaveInPackets;
+ u_long SaveInDiscards;
+ u_long SaveInErrors;
+ u_long SaveInOctets;
+};
+
+struct lqrdata MyLqrData, HisLqrData;
+struct lqrsave HisLqrSave;
+
+/*
+ * We support LQR and ECHO as LQM method
+ */
+#define LQM_LQR 1
+#define LQM_ECHO 2
+
+extern void LqrDump(char *, struct lqrdata *);
+extern void LqrChangeOrder(struct lqrdata *, struct lqrdata *);
+extern void StartLqm(void);
+extern void StopLqr(int);
+extern void RecvEchoLqr(struct mbuf *);
+#endif
diff --git a/usr.sbin/ppp/main.c b/usr.sbin/ppp/main.c
new file mode 100644
index 0000000..0054716
--- /dev/null
+++ b/usr.sbin/ppp/main.c
@@ -0,0 +1,693 @@
+/*
+ * User Process PPP
+ *
+ * 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 Add commands for traffic summary, version display, etc.
+ * o Add signal handler for misc controls.
+ */
+#include "fsm.h"
+#include <fcntl.h>
+#include <sys/time.h>
+#include <termios.h>
+#include <sys/ioctl.h>
+#include <signal.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <netdb.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include "modem.h"
+#include "os.h"
+#include "hdlc.h"
+#include "lcp.h"
+#include "ipcp.h"
+#include "vars.h"
+
+extern void VjInit(), AsyncInit();
+extern void AsyncInput(), IpOutput();
+extern int SelectSystem();
+
+extern void DecodeCommand(), Prompt();
+extern int IsInteractive();
+extern struct in_addr ifnetmask;
+static void DoLoop(void);
+
+static struct termios oldtio; /* Original tty mode */
+static struct termios comtio; /* Command level tty mode */
+static int TermMode;
+static int server, update;
+struct sockaddr_in ifsin;
+
+static void
+TtyInit()
+{
+ struct termios newtio;
+ int stat;
+
+ stat = fcntl(0, F_GETFL, 0);
+ stat |= O_NONBLOCK;
+ fcntl(0, F_SETFL, stat);
+ newtio = oldtio;
+ newtio.c_lflag &= ~(ECHO|ISIG|ICANON);
+ newtio.c_iflag = 0;
+ newtio.c_oflag &= ~OPOST;
+ newtio.c_cc[VEOF] = _POSIX_VDISABLE;
+ newtio.c_cc[VINTR] = _POSIX_VDISABLE;
+ newtio.c_cc[VMIN] = 1;
+ newtio.c_cc[VTIME] = 0;
+ newtio.c_cflag |= CS8;
+ ioctl(0, TIOCSETA, &newtio);
+ comtio = newtio;
+}
+
+/*
+ * Set tty into command mode. We allow canonical input and echo processing.
+ */
+static void
+TtyCommandMode()
+{
+ struct termios newtio;
+ int stat;
+
+ if (!(mode & MODE_INTER))
+ return;
+ ioctl(0, TIOCGETA, &newtio);
+ newtio.c_lflag |= (ECHO|ICANON);
+ newtio.c_iflag = oldtio.c_iflag;
+ newtio.c_oflag |= OPOST;
+ ioctl(0, TIOCSETA, &newtio);
+ stat = fcntl(0, F_GETFL, 0);
+ stat |= O_NONBLOCK;
+ fcntl(0, F_SETFL, stat);
+ TermMode = 0;
+ Prompt(0);
+}
+
+/*
+ * Set tty into terminal mode which is used while we invoke term command.
+ */
+void
+TtyTermMode()
+{
+ int stat;
+
+ ioctl(0, TIOCSETA, &comtio);
+ stat = fcntl(0, F_GETFL, 0);
+ stat &= ~O_NONBLOCK;
+ fcntl(0, F_SETFL, stat);
+ TermMode = 1;
+}
+
+void
+Cleanup(excode)
+int excode;
+{
+ int stat;
+
+ OsLinkdown();
+ stat = fcntl(0, F_GETFL, 0);
+ stat &= ~O_NONBLOCK;
+ fcntl(0, F_SETFL, stat);
+ ioctl(0, TIOCSETA, &oldtio);
+ OsCloseLink(1);
+ sleep(1);
+ if (mode & MODE_AUTO)
+ DeleteIfRoutes(1);
+ OsInterfaceDown(1);
+ LogPrintf(LOG_PHASE, "PPP Terminated.\n");
+ LogClose();
+ if (server > 0)
+ close(server);
+
+ exit(excode);
+}
+
+static void
+Hangup()
+{
+ LogPrintf(LOG_PHASE, "SIGHUP\n");
+ signal(SIGHUP, Hangup);
+ Cleanup(EX_HANGUP);
+}
+
+static void
+CloseSession()
+{
+ LogPrintf(LOG_PHASE, "SIGTERM\n");
+ LcpClose();
+ Cleanup(EX_TERM);
+}
+
+void
+Usage()
+{
+ fprintf(stderr, "Usage: ppp [-auto | -direct -dedicated] [system]\n");
+ exit(EX_START);
+}
+
+void
+ProcessArgs(int argc, char **argv)
+{
+ int optc;
+ char *cp;
+
+ optc = 0;
+ while (argc > 0 && **argv == '-') {
+ cp = *argv + 1;
+ if (strcmp(cp, "auto") == 0)
+ mode |= MODE_AUTO;
+ else if (strcmp(cp, "direct") == 0)
+ mode |= MODE_DIRECT;
+ else if (strcmp(cp, "dedicated") == 0)
+ mode |= MODE_DEDICATED;
+ else
+ Usage();
+ optc++;
+ argv++; argc--;
+ }
+ if (argc > 1) {
+ fprintf(stderr, "specify only one system label.\n");
+ exit(EX_START);
+ }
+ if (argc == 1) dstsystem = *argv;
+
+ if (optc > 1) {
+ fprintf(stderr, "specify only one mode.\n");
+ exit(EX_START);
+ }
+}
+
+static void
+Greetings()
+{
+ printf("User Process PPP. Written by Toshiharu OHNO.\r\n");
+ fflush(stdout);
+}
+
+void
+main(argc, argv)
+int argc;
+char **argv;
+{
+ int tunno;
+ int on = 1;
+
+ argc--; argv++;
+
+ mode = MODE_INTER; /* default operation is interactive mode */
+ netfd = -1;
+ ProcessArgs(argc, argv);
+ Greetings();
+ GetUid();
+ IpcpDefAddress();
+
+ if (SelectSystem("default", CONFFILE) < 0) {
+ fprintf(stderr, "Warning: No default entry is given in config file.\n");
+ }
+
+ if (LogOpen())
+ exit(EX_START);
+
+ if (OpenTunnel(&tunno) < 0) {
+ perror("open_tun");
+ exit(EX_START);
+ }
+
+ if (mode & (MODE_AUTO|MODE_DIRECT|MODE_DEDICATED))
+ mode &= ~MODE_INTER;
+ if (mode & MODE_INTER) {
+ printf("Interactive mode\n");
+ netfd = 0;
+ } else if (mode & MODE_AUTO) {
+ printf("Automatic mode\n");
+ if (dstsystem == NULL) {
+ fprintf(stderr, "Destination system must be specified in auto mode.\n");
+ exit(EX_START);
+ }
+ }
+
+ ioctl(0, TIOCGETA, &oldtio); /* Save original tty mode */
+
+ signal(SIGHUP, Hangup);
+ signal(SIGTERM, CloseSession);
+ signal(SIGINT, CloseSession);
+ signal(SIGSEGV, Hangup);
+
+ if (dstsystem) {
+ if (SelectSystem(dstsystem, CONFFILE) < 0) {
+ fprintf(stderr, "Destination system not found in conf file.\n");
+ Cleanup(EX_START);
+ }
+ if ((mode & MODE_AUTO) && DefHisAddress.ipaddr.s_addr == INADDR_ANY) {
+ fprintf(stderr, "Must specify dstaddr with auto mode.\n");
+ Cleanup(EX_START);
+ }
+ }
+ if (mode & MODE_DIRECT)
+ printf("Packet mode enabled.\n");
+
+#ifdef notdef
+ if (mode & MODE_AUTO) {
+ OsSetIpaddress(IpcpInfo.want_ipaddr, IpcpInfo.his_ipaddr, ifnetmask);
+ }
+#endif
+
+ if (!(mode & MODE_INTER)) {
+ int port = SERVER_PORT + tunno;
+ /*
+ * Create server socket and listen at there.
+ */
+ server = socket(PF_INET, SOCK_STREAM, 0);
+ if (server < 0) {
+ perror("socket");
+ Cleanup(EX_SOCK);
+ }
+ ifsin.sin_family = AF_INET;
+ ifsin.sin_addr.s_addr = INADDR_ANY;
+ ifsin.sin_port = htons(port);
+ if (bind(server, (struct sockaddr *) &ifsin, sizeof(ifsin)) < 0) {
+ perror("bind");
+ if (errno == EADDRINUSE)
+ fprintf(stderr, "Wait for a while, then try again.\n");
+ Cleanup(EX_SOCK);
+ }
+ listen(server, 5);
+
+ DupLog();
+ if (!(mode & MODE_DIRECT)) {
+ if (fork())
+ exit(0);
+ }
+ LogPrintf(LOG_PHASE, "Listening at %d.\n", port);
+#ifdef DOTTYINIT
+ if (mode & (MODE_DIRECT|MODE_DEDICATED)) {
+#else
+ if (mode & MODE_DIRECT) {
+#endif
+ TtyInit();
+ } else {
+ setsid(); /* detach control tty */
+ }
+ } else {
+ server = -1;
+ TtyInit();
+ TtyCommandMode();
+ }
+ LogPrintf(LOG_PHASE, "PPP Started.\n");
+
+
+ do
+ DoLoop();
+ while (mode & MODE_DEDICATED);
+
+ Cleanup(EX_DONE);
+}
+
+/*
+ * Turn into packet mode, where we speek PPP.
+ */
+void
+PacketMode()
+{
+ if (RawModem(modem) < 0) {
+ fprintf(stderr, "Not connected.\r\n");
+ return;
+ }
+
+ AsyncInit();
+ VjInit();
+ LcpInit();
+ IpcpInit();
+ CcpInit();
+ LcpUp();
+
+ if (mode & (MODE_DIRECT|MODE_DEDICATED))
+ LcpOpen(OPEN_ACTIVE);
+ else
+ LcpOpen(VarOpenMode);
+ if ((mode & (MODE_INTER|MODE_AUTO)) == MODE_INTER) {
+ TtyCommandMode();
+ fprintf(stderr, "Packet mode.\r\n");
+ }
+}
+
+static void
+ShowHelp()
+{
+ fprintf(stderr, "Following commands are available\r\n");
+ fprintf(stderr, " ~p\tEnter to Packet mode\r\n");
+ fprintf(stderr, " ~.\tTerminate program\r\n");
+}
+
+static void
+ReadTty()
+{
+ int n;
+ char ch;
+ static int ttystate;
+#define MAXLINESIZE 200
+ char linebuff[MAXLINESIZE];
+
+#ifdef DEBUG
+ logprintf("termode = %d, netfd = %d, mode = %d\n", TermMode, netfd, mode);
+#endif
+ if (!TermMode) {
+ n = read(netfd, linebuff, sizeof(linebuff)-1);
+ if (n > 0)
+ DecodeCommand(linebuff, n, 1);
+ else {
+#ifdef DEBUG
+ logprintf("connection closed.\n");
+#endif
+ close(netfd);
+ netfd = -1;
+ mode &= ~MODE_INTER;
+ }
+ return;
+ }
+
+ /*
+ * We are in terminal mode, decode special sequences
+ */
+ n = read(0, &ch, 1);
+#ifdef DEBUG
+ logprintf("got %d bytes\n", n);
+#endif
+
+ if (n > 0) {
+ switch (ttystate) {
+ case 0:
+ if (ch == '~')
+ ttystate++;
+ else
+ write(modem, &ch, n);
+ break;
+ case 1:
+ switch (ch) {
+ case '?':
+ ShowHelp();
+ break;
+ case '-':
+ if (loglevel > 0) {
+ loglevel--;
+ fprintf(stderr, "New loglevel is %d\r\n", loglevel);
+ }
+ break;
+ case '+':
+ loglevel++;
+ fprintf(stderr, "New loglevel is %d\r\n", loglevel);
+ break;
+#ifdef DEBUG
+ case 'm':
+ ShowMemMap();
+ break;
+#endif
+ case 'p':
+ /*
+ * XXX: Should check carrier.
+ */
+ if (LcpFsm.state <= ST_CLOSED) {
+ VarOpenMode = OPEN_ACTIVE;
+ PacketMode();
+ }
+ break;
+#ifdef DEBUG
+ case 't':
+ ShowTimers();
+ break;
+#endif
+ case '.':
+ TermMode = 1;
+ TtyCommandMode();
+ break;
+ default:
+ if (write(modem, &ch, n) < 0)
+ fprintf(stderr, "err in write.\r\n");
+ break;
+ }
+ ttystate = 0;
+ break;
+ }
+ }
+}
+
+
+/*
+ * Here, we'll try to detect HDLC frame
+ */
+
+static char *FrameHeaders[] = {
+ "\176\177\175\043",
+ "\176\377\175\043",
+ "\176\175\137\175\043",
+ "\176\175\337\175\043",
+ NULL,
+};
+
+u_char *
+HdlcDetect(cp, n)
+u_char *cp;
+int n;
+{
+ char *ptr, **hp;
+
+ cp[n] = '\0'; /* be sure to null terminated */
+ ptr = NULL;
+ for (hp = FrameHeaders; *hp; hp++) {
+ if (ptr = strstr((char *)cp, *hp))
+ break;
+ }
+ return((u_char *)ptr);
+}
+
+static struct pppTimer RedialTimer;
+
+static void
+RedialTimeout()
+{
+ StopTimer(&RedialTimer);
+ LogPrintf(LOG_PHASE, "Redialing timer expired.\n");
+}
+
+static void
+StartRedialTimer()
+{
+ LogPrintf(LOG_PHASE, "Enter pause for redialing.\n");
+ StopTimer(&RedialTimer);
+ RedialTimer.state = TIMER_STOPPED;
+ RedialTimer.load = REDIAL_PERIOD * SECTICKS;
+ RedialTimer.func = RedialTimeout;
+ StartTimer(&RedialTimer);
+}
+
+
+static void
+DoLoop()
+{
+ fd_set rfds, wfds, efds;
+ int pri, i, n, wfd;
+ struct sockaddr_in hisaddr;
+ struct timeval timeout, *tp;
+ int ssize = sizeof(hisaddr);
+ u_char *cp;
+ u_char rbuff[MAX_MRU];
+
+ if (mode & MODE_DIRECT) {
+ modem = OpenModem(mode);
+ fprintf(stderr, "Packet mode enabled\n");
+ PacketMode();
+ } else if (mode & MODE_DEDICATED) {
+ if (!modem)
+ modem = OpenModem(mode);
+ }
+
+ fflush(stdout);
+
+ timeout.tv_sec = 0;;
+ timeout.tv_usec = 0;
+
+ for (;;) {
+ IpStartOutput();
+ FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds);
+ FD_SET(tun_in, &rfds);
+ if (server > 0) FD_SET(server, &rfds);
+
+ /* *** IMPORTANT ***
+ *
+ * CPU is serviced every TICKUNIT micro seconds.
+ * This value must be chosen with great care. If this values is
+ * too big, it results loss of characters from modem and poor responce.
+ * If this values is too small, ppp process eats many CPU time.
+ */
+ usleep(TICKUNIT);
+ TimerService();
+
+ if (modem) {
+ FD_SET(modem, &rfds);
+ FD_SET(modem, &efds);
+ FD_SET(modem, &wfds);
+ }
+ if (netfd > -1) {
+ FD_SET(netfd, &rfds);
+ FD_SET(netfd, &efds);
+ }
+ /*
+ * Normally, slect() will not block because modem is writable.
+ * In AUTO mode, select will block until we find packet from tun.
+ * However, we have to run ourselves while we are in redial wait state.
+ */
+ tp = (RedialTimer.state == TIMER_RUNNING)? &timeout : NULL;
+ i = select(tun_in+10, &rfds, &wfds, &efds, tp);
+ if (i == 0) {
+ continue;
+ }
+ if (i < 0) {
+ perror("select");
+ break;
+ }
+ if ((netfd > 0 && FD_ISSET(netfd, &efds)) || FD_ISSET(modem, &efds)) {
+ logprintf("Exception detected.\n");
+ break;
+ }
+
+ if (server > 0 && FD_ISSET(server, &rfds)) {
+#ifdef DEBUG
+ logprintf("connected to client.\n");
+#endif
+ wfd = accept(server, (struct sockaddr *)&hisaddr, &ssize);
+ if (netfd > 0) {
+ write(wfd, "already in use.\n", 16);
+ close(wfd);
+ continue;
+ } else
+ netfd = wfd;
+ if (dup2(netfd, 1) < 0)
+ perror("dup2");
+ mode |= MODE_INTER;
+ Greetings();
+ (void) IsInteractive();
+ Prompt(0);
+ }
+
+ if ((mode & MODE_INTER) && FD_ISSET(netfd, &rfds)) {
+ /* something to read from tty */
+ ReadTty();
+ }
+ if (modem) {
+ if (FD_ISSET(modem, &wfds)) { /* ready to write into modem */
+ ModemStartOutput(modem);
+ }
+ if (FD_ISSET(modem, &rfds)) { /* something to read from modem */
+ n = read(modem, rbuff, sizeof(rbuff));
+ if ((mode & MODE_DIRECT) && n <= 0) {
+ DownConnection();
+ } else
+ LogDumpBuff(LOG_ASYNC, "ReadFromModem", rbuff, n);
+
+ if (LcpFsm.state <= ST_CLOSED) {
+ /*
+ * In dedicated mode, we just discard input until LCP is started.
+ */
+ if (!(mode & MODE_DEDICATED)) {
+ cp = HdlcDetect(rbuff, n);
+ if (cp) {
+ /*
+ * LCP packet is detected. Turn ourselves into packet mode.
+ */
+ if (cp != rbuff) {
+ write(1, rbuff, cp - rbuff);
+ write(1, "\r\n", 2);
+ }
+ PacketMode();
+#ifdef notdef
+ AsyncInput(cp, n - (cp - rbuff));
+#endif
+ } else
+ write(1, rbuff, n);
+ }
+ } else {
+ if (n > 0)
+ AsyncInput(rbuff, n);
+#ifdef notdef
+ continue; /* THIS LINE RESULT AS POOR PERFORMANCE */
+#endif
+ }
+ }
+ }
+ if (FD_ISSET(tun_in, &rfds)) { /* something to read from tun */
+ /*
+ * If there are many packets queued, wait until they are drained.
+ */
+ if (ModemQlen() > 5)
+ continue;
+
+ n = read(tun_in, rbuff, sizeof(rbuff));
+ if (n < 0) {
+ perror("read from tun");
+ continue;
+ }
+ /*
+ * Process on-demand dialup. Output packets are queued within tunnel
+ * device until IPCP is opened.
+ */
+ if (LcpFsm.state <= ST_CLOSED && (mode & MODE_AUTO)) {
+ pri = PacketCheck(rbuff, n, 2);
+ if (pri >= 0) {
+ if (RedialTimer.state == TIMER_RUNNING) {
+ /*
+ * We are in redial wait state. Ignore packet.
+ */
+ continue;
+ }
+ modem = OpenModem(mode);
+#ifdef DEBUG
+ logprintf("going to dial: modem = %d\n", modem);
+#endif
+ if (modem < 0) {
+ printf("failed to open modem.\n");
+ Cleanup(EX_MODEM);
+ }
+
+ if (DialModem()) {
+ sleep(1); /* little pause to allow peer starts */
+ ModemTimeout();
+ PacketMode();
+ } else {
+#ifdef notdef
+ Cleanup(EX_DIAL);
+#endif
+ CloseModem();
+ /* Dial failed. Keep quite during redial wait period. */
+ /* XXX: We shoud implement re-dial */
+ StartRedialTimer();
+ continue;
+ }
+ IpEnqueue(pri, rbuff, n);
+ }
+ continue;
+ }
+ pri = PacketCheck(rbuff, n, 1);
+ if (pri >= 0)
+ IpEnqueue(pri, rbuff, n);
+ }
+ }
+ logprintf("job done.\n");
+}
diff --git a/usr.sbin/ppp/mbuf.c b/usr.sbin/ppp/mbuf.c
new file mode 100644
index 0000000..2486569
--- /dev/null
+++ b/usr.sbin/ppp/mbuf.c
@@ -0,0 +1,187 @@
+/*
+ * PPP Memory handling 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:
+ */
+#include "defs.h"
+
+struct memmap {
+ struct mbuf *queue;
+ int count;
+} MemMap[MB_MAX+2];
+
+static int totalalloced;
+
+int
+plength(bp)
+struct mbuf *bp;
+{
+ int len;
+
+ for (len = 0; bp; bp = bp->next)
+ len += bp->cnt;
+ return(len);
+}
+
+struct mbuf *
+mballoc(cnt, type)
+int cnt;
+int type;
+{
+ u_char *p;
+ struct mbuf *bp;
+
+ if (type > MB_MAX)
+ logprintf("bad type %d\n", type);
+ bp = (struct mbuf *)malloc(sizeof(struct mbuf));
+ bzero(bp, sizeof(struct mbuf));
+ p = (u_char *)malloc(cnt);
+ MemMap[type].count += cnt;
+ totalalloced += cnt;
+ bp->base = p;
+ bp->size = bp->cnt = cnt;
+ bp->type = type;
+ return(bp);
+}
+
+struct mbuf *
+mbfree(struct mbuf *bp)
+{
+ struct mbuf *nbp;
+
+ if (bp) {
+ nbp = bp->next;
+ MemMap[bp->type].count -= bp->size;
+ totalalloced -= bp->size;
+ free(bp->base);
+ free(bp);
+ return(nbp);
+ }
+ return(bp);
+}
+
+void
+pfree(struct mbuf *bp)
+{
+ while (bp)
+ bp = mbfree(bp);
+}
+
+struct mbuf *
+mbread(bp, ptr, len)
+struct mbuf *bp;
+u_char *ptr;
+int len;
+{
+ int nb;
+
+ while (bp && len > 0) {
+ if (len > bp->cnt)
+ nb = bp->cnt;
+ else
+ nb = len;
+ bcopy(MBUF_CTOP(bp), ptr, nb);
+ ptr += nb;
+ bp->cnt -= nb;
+ len -= nb;
+ bp->offset += nb;
+ if (bp->cnt == 0) {
+#ifdef notdef
+ bp = bp->next;
+#else
+ bp = mbfree(bp);
+#endif
+ }
+ }
+ return(bp);
+}
+
+void
+mbwrite(bp, ptr, cnt)
+struct mbuf *bp;
+u_char *ptr;
+int cnt;
+{
+ int plen;
+ int nb;
+
+ plen = plength(bp);
+ if (plen < cnt)
+ cnt = plen;
+
+ while (cnt > 0) {
+ nb = (cnt < bp->cnt)? cnt : bp->cnt;
+ bcopy(ptr, MBUF_CTOP(bp), nb);
+ cnt -= bp->cnt;
+ bp = bp->next;
+ }
+}
+
+void
+DumpBp(bp)
+struct mbuf *bp;
+{
+ u_char *cp;
+ int cnt, loc;
+
+ logprintf("dump bp = %x (%d)\n", bp, plength(bp));
+ loc = 0;
+ while (bp) {
+ cp = MBUF_CTOP(bp);
+ cnt = bp->cnt;
+ while (cnt > 0) {
+ logprintf("%02x", *cp++);
+ loc++;
+ if (loc == 16) {
+ loc = 0;
+ logprintf("\n");
+ } else
+ logprintf(" ");
+ cnt--;
+ }
+ bp = bp->next;
+ }
+ if (loc) logprintf("\n");
+}
+
+int
+ShowMemMap()
+{
+ int i;
+
+ for (i = 0; i <= MB_MAX; i += 2) {
+ printf("%d: %d %d: %d\r\n",
+ i, MemMap[i].count, i+1, MemMap[i+1].count);
+ }
+ return(1);
+}
+
+void
+LogMemory()
+{
+#ifdef DEBUG
+ logprintf("mem alloced: %d\n", totalalloced);
+ logprintf(" 1: %d 2: %d 3: %d 4: %d\n",
+ MemMap[1].count, MemMap[2].count, MemMap[3].count, MemMap[4].count);
+ logprintf(" 5: %d 6: %d 7: %d 8: %d\n",
+ MemMap[5].count, MemMap[6].count, MemMap[7].count, MemMap[8].count);
+#endif
+}
diff --git a/usr.sbin/ppp/mbuf.h b/usr.sbin/ppp/mbuf.h
new file mode 100644
index 0000000..10cb67e
--- /dev/null
+++ b/usr.sbin/ppp/mbuf.h
@@ -0,0 +1,67 @@
+/*
+ * 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. 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:
+ */
+
+#ifndef _MBUF_H_
+#define _MBUF_H_
+
+struct mbuf {
+ u_char *base; /* pointer to top of buffer space */
+ short size; /* size allocated from base */
+ short offset; /* offset to start position */
+ short cnt; /* available byte count in buffer */
+ short type;
+ struct mbuf *next; /* link to next mbuf */
+ struct mbuf *pnext; /* link to next packet */
+};
+
+struct mqueue {
+ struct mbuf *top;
+ struct mbuf *last;
+ int qlen;
+};
+
+#define NULLBUFF ((struct mbuf *)0)
+
+#define MBUF_CTOP(bp) (bp->base + bp->offset)
+
+#define MB_ASYNC 1
+#define MB_FSM 2
+#define MB_HDLCOUT 3
+#define MB_IPIN 4
+#define MB_ECHO 5
+#define MB_LQR 6
+#define MB_MODEM 7
+#define MB_VJCOMP 8
+#define MB_LOG 9
+#define MB_IPQ 10
+#define MB_MAX MB_IPQ
+
+extern int plength(struct mbuf *bp);
+extern struct mbuf *mballoc(int cnt, int type);
+extern struct mbuf *mbfree(struct mbuf *bp);
+extern void pfree(struct mbuf *bp);
+extern void mbwrite(struct mbuf *bp, u_char *ptr, int cnt);
+extern struct mbuf *mbread(struct mbuf *bp, u_char *ptr, int cnt);
+extern void DumpBp(struct mbuf *bp);
+extern void Enqueue(struct mqueue *queue, struct mbuf *bp);
+extern struct mbuf *Dequeue(struct mqueue *queue);
+#endif
diff --git a/usr.sbin/ppp/md5.h b/usr.sbin/ppp/md5.h
new file mode 100644
index 0000000..dc07614
--- /dev/null
+++ b/usr.sbin/ppp/md5.h
@@ -0,0 +1,38 @@
+/*
+ * MD5.H - header file for MD5C.C
+ *
+ * Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+ * rights reserved.
+ *
+ * License to copy and use this software is granted provided that it
+ * is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+ * Algorithm" in all material mentioning or referencing this software
+ * or this function.
+ *
+ * License is also granted to make and use derivative works provided
+ * that such works are identified as "derived from the RSA Data
+ * Security, Inc. MD5 Message-Digest Algorithm" in all material
+ * mentioning or referencing the derived work.
+ *
+ * RSA Data Security, Inc. makes no representations concerning either
+ * the merchantability of this software or the suitability of this
+ * software for any particular purpose. It is provided "as is"
+ * without express or implied warranty of any kind.
+ * These notices must be retained in any copies of any part of this
+ * documentation and/or software.
+ *
+ * $Id:$
+ *
+ */
+
+/* MD5 context. */
+typedef struct {
+ UINT4 state[4]; /* state (ABCD) */
+ UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */
+ unsigned char buffer[64]; /* input buffer */
+} MD5_CTX;
+
+void MD5Init PROTO_LIST ((MD5_CTX *));
+void MD5Update PROTO_LIST
+ ((MD5_CTX *, unsigned char *, unsigned int));
+void MD5Final PROTO_LIST ((unsigned char [16], MD5_CTX *));
diff --git a/usr.sbin/ppp/md5c.c b/usr.sbin/ppp/md5c.c
new file mode 100644
index 0000000..886c95b
--- /dev/null
+++ b/usr.sbin/ppp/md5c.c
@@ -0,0 +1,338 @@
+/*
+ * MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
+ *
+ * Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+ * rights reserved.
+ *
+ * License to copy and use this software is granted provided that it
+ * is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+ * Algorithm" in all material mentioning or referencing this software
+ * or this function.
+ *
+ * License is also granted to make and use derivative works provided
+ * that such works are identified as "derived from the RSA Data
+ * Security, Inc. MD5 Message-Digest Algorithm" in all material
+ * mentioning or referencing the derived work.
+ *
+ * RSA Data Security, Inc. makes no representations concerning either
+ * the merchantability of this software or the suitability of this
+ * software for any particular purpose. It is provided "as is"
+ * without express or implied warranty of any kind.
+ *
+ * These notices must be retained in any copies of any part of this
+ * documentation and/or software.
+ *
+ * $Id:$
+ *
+ */
+
+#include "global.h"
+#include "md5.h"
+
+/* Constants for MD5Transform routine.
+ */
+
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+
+static void MD5Transform PROTO_LIST ((UINT4 [4], unsigned char [64]));
+static void Encode PROTO_LIST
+ ((unsigned char *, UINT4 *, unsigned int));
+static void Decode PROTO_LIST
+ ((UINT4 *, unsigned char *, unsigned int));
+static void MD5_memcpy PROTO_LIST ((POINTER, POINTER, unsigned int));
+static void MD5_memset PROTO_LIST ((POINTER, int, unsigned int));
+
+static unsigned char PADDING[64] = {
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/* F, G, H and I are basic MD5 functions.
+ */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | (~z)))
+
+/* ROTATE_LEFT rotates x left n bits.
+ */
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
+Rotation is separate from addition to prevent recomputation.
+ */
+#define FF(a, b, c, d, x, s, ac) { \
+ (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define GG(a, b, c, d, x, s, ac) { \
+ (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define HH(a, b, c, d, x, s, ac) { \
+ (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define II(a, b, c, d, x, s, ac) { \
+ (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+
+/* MD5 initialization. Begins an MD5 operation, writing a new context.
+ */
+void MD5Init (context)
+MD5_CTX *context; /* context */
+{
+ context->count[0] = context->count[1] = 0;
+ /* Load magic initialization constants.
+*/
+ context->state[0] = 0x67452301;
+ context->state[1] = 0xefcdab89;
+ context->state[2] = 0x98badcfe;
+ context->state[3] = 0x10325476;
+}
+
+/* MD5 block update operation. Continues an MD5 message-digest
+ operation, processing another message block, and updating the
+ context.
+ */
+void MD5Update (context, input, inputLen)
+MD5_CTX *context; /* context */
+unsigned char *input; /* input block */
+unsigned int inputLen; /* length of input block */
+{
+ unsigned int i, index, partLen;
+
+ /* Compute number of bytes mod 64 */
+ index = (unsigned int)((context->count[0] >> 3) & 0x3F);
+
+ /* Update number of bits */
+ if ((context->count[0] += ((UINT4)inputLen << 3))
+ < ((UINT4)inputLen << 3))
+ context->count[1]++;
+ context->count[1] += ((UINT4)inputLen >> 29);
+
+ partLen = 64 - index;
+
+ /* Transform as many times as possible.
+*/
+ if (inputLen >= partLen) {
+ MD5_memcpy
+ ((POINTER)&context->buffer[index], (POINTER)input, partLen);
+ MD5Transform (context->state, context->buffer);
+
+ for (i = partLen; i + 63 < inputLen; i += 64)
+ MD5Transform (context->state, &input[i]);
+
+ index = 0;
+ }
+ else
+ i = 0;
+
+ /* Buffer remaining input */
+ MD5_memcpy
+ ((POINTER)&context->buffer[index], (POINTER)&input[i],
+ inputLen-i);
+}
+
+/* MD5 finalization. Ends an MD5 message-digest operation, writing the
+ the message digest and zeroizing the context.
+ */
+void MD5Final (digest, context)
+unsigned char digest[16]; /* message digest */
+MD5_CTX *context; /* context */
+{
+ unsigned char bits[8];
+ unsigned int index, padLen;
+
+ /* Save number of bits */
+ Encode (bits, context->count, 8);
+
+ /* Pad out to 56 mod 64.
+*/
+ index = (unsigned int)((context->count[0] >> 3) & 0x3f);
+ padLen = (index < 56) ? (56 - index) : (120 - index);
+ MD5Update (context, PADDING, padLen);
+
+ /* Append length (before padding) */
+ MD5Update (context, bits, 8);
+
+ /* Store state in digest */
+ Encode (digest, context->state, 16);
+
+ /* Zeroize sensitive information.
+*/
+ MD5_memset ((POINTER)context, 0, sizeof (*context));
+}
+
+/* MD5 basic transformation. Transforms state based on block.
+ */
+static void MD5Transform (state, block)
+UINT4 state[4];
+unsigned char block[64];
+{
+ UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
+
+ Decode (x, block, 64);
+
+ /* Round 1 */
+ FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
+ FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
+ FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
+ FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
+ FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
+ FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
+ FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
+ FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
+ FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
+ FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
+ FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
+ FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
+ FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
+ FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
+ FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
+ FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
+
+ /* Round 2 */
+ GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
+ GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
+ GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
+ GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
+ GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
+ GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
+ GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
+ GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
+ GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
+ GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
+ GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
+ GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
+ GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
+ GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
+ GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
+ GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
+
+ /* Round 3 */
+ HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
+ HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
+ HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
+ HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
+ HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
+ HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
+ HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
+ HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
+ HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
+ HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
+ HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
+ HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
+ HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
+ HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
+ HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
+ HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
+
+ /* Round 4 */
+ II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
+ II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
+ II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
+ II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
+ II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
+ II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
+ II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
+ II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
+ II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
+ II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
+ II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
+ II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
+ II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
+ II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
+ II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
+ II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
+
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+
+ /* Zeroize sensitive information.
+ */
+ MD5_memset ((POINTER)x, 0, sizeof (x));
+}
+
+/* Encodes input (UINT4) into output (unsigned char). Assumes len is
+ a multiple of 4.
+ */
+static void Encode (output, input, len)
+unsigned char *output;
+UINT4 *input;
+unsigned int len;
+{
+ unsigned int i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4) {
+ output[j] = (unsigned char)(input[i] & 0xff);
+ output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
+ output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
+ output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
+ }
+}
+
+/* Decodes input (unsigned char) into output (UINT4). Assumes len is
+ a multiple of 4.
+ */
+static void Decode (output, input, len)
+UINT4 *output;
+unsigned char *input;
+unsigned int len;
+{
+ unsigned int i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4)
+ output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) |
+ (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
+}
+
+/* Note: Replace "for loop" with standard memcpy if possible.
+ */
+
+static void MD5_memcpy (output, input, len)
+POINTER output;
+POINTER input;
+unsigned int len;
+{
+ unsigned int i;
+
+ for (i = 0; i < len; i++)
+ output[i] = input[i];
+}
+
+/* Note: Replace "for loop" with standard memset if possible.
+ */
+static void MD5_memset (output, value, len)
+POINTER output;
+int value;
+unsigned int len;
+{
+ unsigned int i;
+
+ for (i = 0; i < len; i++)
+ ((char *)output)[i] = (char)value;
+}
diff --git a/usr.sbin/ppp/modem.c b/usr.sbin/ppp/modem.c
new file mode 100644
index 0000000..b9775b8
--- /dev/null
+++ b/usr.sbin/ppp/modem.c
@@ -0,0 +1,591 @@
+/*
+ * PPP Modem handling 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:
+ */
+#include "fsm.h"
+#include <fcntl.h>
+#include <termios.h>
+#include <sys/ioctl.h>
+#include "hdlc.h"
+#include "lcp.h"
+#include "modem.h"
+#include "vars.h"
+
+extern int DoChat();
+
+static int mbits; /* Current DCD status */
+static int connect_time; /* connection time */
+static int connect_count;
+static struct pppTimer ModemTimer;
+static char *uucplock;
+
+extern int uu_lock(), uu_unlock();
+extern void PacketMode();
+
+#define Online (mbits & TIOCM_CD)
+
+static struct mbuf *modemout;
+static struct mqueue OutputQueues[PRI_URGENT+1];
+static int dev_is_modem;
+
+void
+Enqueue(queue, bp)
+struct mqueue *queue;
+struct mbuf *bp;
+{
+ if (queue->last) {
+ queue->last->pnext = bp;
+ queue->last = bp;
+ } else
+ queue->last = queue->top = bp;
+ queue->qlen++;
+#ifdef QDEBUG
+ logprintf("Enqueue: len = %d\n", queue->qlen);
+#endif
+}
+
+struct mbuf *
+Dequeue(queue)
+struct mqueue *queue;
+{
+ struct mbuf *bp;
+
+#ifdef QDEBUG
+ logprintf("Dequeue: len = %d\n", queue->qlen);
+#endif
+ if (bp = queue->top) {
+ queue->top = queue->top->pnext;
+ queue->qlen--;
+ if (queue->top == NULL) {
+ queue->last = queue->top;
+#ifdef QDEBUG
+ if (queue->qlen)
+ logprintf("!!! not zero (%d)!!!\n", queue->qlen);
+#endif
+ }
+ }
+ return(bp);
+}
+
+static time_t uptime;
+
+void
+DownConnection()
+{
+ LogPrintf(LOG_PHASE, "Disconnected!\n");
+ LogPrintf(LOG_PHASE, "Connect time: %d secs\n", time(NULL) - uptime);
+ LcpDown();
+ connect_time = 0;
+}
+
+/*
+ * ModemTimeout() watches DCD signal and notifies if it's status is changed.
+ *
+ */
+void
+ModemTimeout()
+{
+ int ombits = mbits;
+ int change;
+
+ StopTimer(&ModemTimer);
+ if (Online)
+ connect_time++;
+ StartTimer(&ModemTimer);
+
+ if (dev_is_modem) {
+ ioctl(modem, TIOCMGET, &mbits);
+ change = ombits ^ mbits;
+ if (change & TIOCM_CD) {
+ if (Online) {
+ time(&uptime);
+ LogPrintf(LOG_PHASE, "*Connected!\n");
+ connect_count++;
+ /*
+ * In dedicated mode, start packet mode immediate
+ * after we detected carrier.
+ */
+ if (mode & MODE_DEDICATED)
+ PacketMode();
+ } else {
+ DownConnection();
+ }
+ }
+ } else {
+ if (!Online) {
+online:
+ time(&uptime);
+ LogPrintf(LOG_PHASE, "Connected!\n");
+ mbits = TIOCM_CD;
+ connect_count++;
+ connect_time = 0;
+ }
+ }
+}
+
+void
+StartModemTimer()
+{
+ connect_time = 0;
+ StopTimer(&ModemTimer);
+ ModemTimer.state = TIMER_STOPPED;
+ ModemTimer.load = SECTICKS;
+ ModemTimer.func = ModemTimeout;
+ StartTimer(&ModemTimer);
+}
+
+struct parity {
+ char *name;
+ char *name1;
+ int set;
+} validparity[] = {
+ { "even", "P_EVEN", CS7 | PARENB }, { "odd", "P_ODD", CS7 | PARENB | PARODD },
+ { "none", "P_ZERO", CS8 }, { NULL, 0 },
+};
+
+int
+GetParityValue(str)
+char *str;
+{
+ struct parity *pp;
+
+ for (pp = validparity; pp->name; pp++) {
+ if (strcasecmp(pp->name, str) == 0 ||
+ strcasecmp(pp->name1, str) == 0) {
+ VarParity = pp->set;
+ return(pp->set);
+ }
+ }
+ return(-1);
+}
+
+int
+ChangeParity(str)
+char *str;
+{
+ struct termios rstio;
+ int val;
+
+ val = GetParityValue(str);
+ if (val > 0) {
+ VarParity = val;
+ ioctl(modem, TIOCGETA, &rstio);
+ rstio.c_cflag &= ~(CSIZE|PARODD|PARENB);
+ rstio.c_cflag |= val;
+ ioctl(modem, TIOCSETA, &rstio);
+ }
+ return(val);
+}
+
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+int
+OpenConnection(host, port)
+char *host, *port;
+{
+ struct sockaddr_in dest;
+ int sock;
+ struct hostent *hp;
+ struct servent *sp;
+
+ dest.sin_family = AF_INET;
+ dest.sin_addr.s_addr = inet_addr(host);
+ if (dest.sin_addr.s_addr == INADDR_NONE) {
+ hp = gethostbyname(host);
+ if (hp) {
+ bcopy(hp->h_addr_list[0], &dest.sin_addr.s_addr, 4);
+ } else {
+ printf("unknown host: %s\n", host);
+ return(-1);
+ }
+ }
+ dest.sin_port = htons(atoi(port));
+ if (dest.sin_port == 0) {
+ sp = getservbyname(port, "tcp");
+ if (sp) {
+ dest.sin_port = sp->s_port;
+ } else {
+ printf("unknown service: %s\n", port);
+ return(-1);
+ }
+ }
+ LogPrintf(LOG_PHASE, "Connected to %s:%s\n", host, port);
+
+ sock = socket(PF_INET, SOCK_STREAM, 0);
+ if (sock < 0) {
+ return(sock);
+ }
+ if (connect(sock, (struct sockaddr *)&dest, sizeof(dest)) < 0) {
+ printf("connection failed.\n");
+ return(-1);
+ }
+ return(sock);
+}
+
+int
+OpenModem(mode)
+int mode;
+{
+ struct termios rstio;
+ int oldflag;
+ char *host, *cp, *port;
+
+ mbits = 0;
+ if (mode & MODE_DIRECT) {
+ if (isatty(0))
+ modem = open("/dev/tty", O_RDWR|O_NONBLOCK);
+ } else if (modem == 0) {
+ if (strncmp(VarDevice, "/dev", 4) == 0) {
+ uucplock = rindex(VarDevice, '/')+1;
+ if (uu_lock(uucplock) < 0) {
+ fprintf(stderr, "modem is in use.\n");
+ return(-1);
+ }
+ modem = open(VarDevice, O_RDWR|O_NONBLOCK);
+ if (modem < 0) {
+ perror("open modem");
+ return(modem);
+ }
+ } else {
+ /* XXX: PPP over TCP */
+ cp = index(VarDevice, ':');
+ if (cp) {
+ *cp = 0;
+ host = VarDevice;
+ port = cp + 1;
+ if (*host && *port) {
+ modem = OpenConnection(host, port);
+ *cp = ':'; /* Don't destroy VarDevice */
+ if (modem < 0) return(-1);
+ } else {
+ *cp = ':'; /* Don't destroy VarDevice */
+ return(-1);
+ }
+ } else
+ return(-1);
+ }
+ }
+
+ while (modem < 3)
+ modem = dup(modem);
+
+ /*
+ * If we are working on tty device, change it's mode into
+ * the one desired for further operation. In this implementation,
+ * we assume that modem is configuted to use CTS/RTS flow control.
+ */
+ if (dev_is_modem = isatty(modem)) {
+ ioctl(modem, TIOCGETA, &rstio);
+#ifdef DEBUG
+ logprintf("## modem = %d\n", modem);
+ logprintf("modem (get): iflag = %x, oflag = %x, cflag = %x\n",
+ rstio.c_iflag, rstio.c_oflag, rstio.c_cflag);
+#endif
+#define USE_CTSRTS
+#ifdef USE_CTSRTS
+ rstio.c_cflag = (CS8 | CREAD | CLOCAL | CCTS_OFLOW|CRTS_IFLOW);
+#else
+ rstio.c_cflag = (CS8 | CREAD | CLOCAL);
+#endif
+ if ((mode & MODE_DIRECT) == 0) {
+ /*
+ * If we are working as direct mode, don't change tty speed.
+ */
+ rstio.c_cflag &= ~(CSIZE|PARENB|PARODD);
+ rstio.c_cflag |= VarParity;
+ rstio.c_ispeed = rstio.c_ospeed = VarSpeed;
+ }
+ rstio.c_iflag |= (IGNBRK | ISTRIP | IGNPAR | IXON | IXOFF);
+ rstio.c_iflag &= ~(BRKINT|ICRNL|IXANY|IMAXBEL);
+ rstio.c_lflag = 0;
+
+ rstio.c_oflag &= ~OPOST;
+#ifdef notdef
+ rstio.c_cc[VMIN] = 10;
+ rstio.c_cc[VTIME] = 1;
+#else
+ rstio.c_cc[VMIN] = 1;
+ rstio.c_cc[VTIME] = 0;
+#endif
+ ioctl(modem, TIOCSETA, &rstio);
+#ifdef DEBUG
+ logprintf("modem (put): iflag = %x, oflag = %x, cflag = %x\n",
+ rstio.c_iflag, rstio.c_oflag, rstio.c_cflag);
+#endif
+
+#ifdef DEBUG
+ ioctl(modem, TIOCMGET, &mbits);
+ fprintf(stderr, "modem control = %o\n", mbits);
+#endif
+
+ oldflag = fcntl(modem, F_GETFL, 0);
+ fcntl(modem, F_SETFL, oldflag & ~O_NDELAY);
+ }
+ StartModemTimer();
+
+ return(modem);
+}
+
+int
+ModemSpeed()
+{
+ struct termios rstio;
+
+ ioctl(modem, TIOCGETA, &rstio);
+ return(rstio.c_ispeed);
+}
+
+static struct termios modemios;
+
+/*
+ * Put modem tty line into raw mode which is necessary in packet mode operation
+ */
+int
+RawModem(modem)
+int modem;
+{
+ struct termios rstio;
+ int oldflag;
+
+ if (!isatty(modem))
+ return(0);
+ if (!(mode & MODE_DIRECT) && modem && !Online) {
+#ifdef DEBUG
+ logprintf("mode = %d, modem = %d, mbits = %x\n", mode, modem, mbits);
+#endif
+#ifdef notdef
+ return(-1);
+#endif
+ }
+ ioctl(modem, TIOCGETA, &rstio);
+ modemios = rstio;
+ rstio.c_cflag &= ~(CSIZE|PARENB|PARODD);
+ rstio.c_cflag |= CS8;
+ rstio.c_iflag &= ~(ISTRIP|IXON|IXOFF|BRKINT|ICRNL|INLCR);
+ ioctl(modem, TIOCSETA, &rstio);
+ oldflag = fcntl(modem, F_GETFL, 0);
+ fcntl(modem, F_SETFL, oldflag | O_NDELAY);
+#ifdef DEBUG
+ oldflag = fcntl(modem, F_GETFL, 0);
+ logprintf("modem (put2): iflag = %x, oflag = %x, cflag = %x\n",
+ rstio.c_iflag, rstio.c_oflag, rstio.c_cflag);
+ logprintf("flag = %x\n", oldflag);
+#endif
+ return(0);
+}
+
+void
+UnrawModem(modem)
+int modem;
+{
+ int oldflag;
+
+ if (isatty(modem)) {
+ ioctl(modem, TIOCSETA, &modemios);
+ oldflag = fcntl(modem, F_GETFL, 0);
+ fcntl(modem, F_SETFL, oldflag & ~O_NDELAY);
+ }
+}
+
+void
+HangupModem(flag)
+int flag;
+{
+ int n = 0;
+
+ if (!isatty(modem)) {
+ mbits &= ~TIOCM_DTR;
+ close(modem);
+ modem = 0; /* Mark as modem has closed */
+ return;
+ }
+
+ if (Online) {
+ mbits &= ~TIOCM_DTR;
+ ioctl(modem, TIOCMSET, &mbits);
+ sleep(1);
+#ifdef notdef
+ mbits &= ~TIOCM_CD;
+#endif
+ }
+ /*
+ * If we are working as dedicated mode, never close it
+ * until we are directed to quit program.
+ */
+ if (modem && (flag || !(mode & MODE_DEDICATED))) {
+ ModemTimeout(); /* XXX */
+ StopTimer(&ModemTimer); /* XXX */
+ ioctl(modem, TIOCFLUSH, &n);
+ UnrawModem(modem);
+ close(modem);
+ (void) uu_unlock(uucplock);
+ modem = 0; /* Mark as modem has closed */
+ } else {
+ mbits |= TIOCM_DTR;
+ ioctl(modem, TIOCMSET, &mbits);
+ }
+}
+
+CloseModem()
+{
+ close(modem);
+ modem = 0;
+ (void) uu_unlock(uucplock);
+}
+
+/*
+ * Write to modem. Actualy, requested packets are queued, and goes out
+ * to the line when ModemStartOutput() is called.
+ */
+void
+WriteModem(pri, ptr, count)
+int pri;
+char *ptr;
+int count;
+{
+ struct mbuf *bp;
+
+ bp = mballoc(count, MB_MODEM);
+ bcopy(ptr, MBUF_CTOP(bp), count);
+ Enqueue(&OutputQueues[pri], bp);
+}
+
+int
+ModemQlen()
+{
+ struct mbuf *bp;
+ int len = 0;
+ int i;
+
+ for (i = PRI_NORMAL; i <= PRI_URGENT; i++) {
+ for (bp = OutputQueues[i].top; bp; bp = bp->pnext)
+ len++;
+ }
+
+ return(len);
+}
+
+void
+ModemStartOutput(fd)
+int fd;
+{
+ struct mqueue *queue;
+ int nb, nw, i;
+
+ if (modemout == NULL) {
+ i = 0;
+ for (queue = &OutputQueues[PRI_URGENT]; queue >= OutputQueues; queue--) {
+ if (queue->top) {
+ modemout = Dequeue(queue);
+#ifdef QDEBUG
+ if (i < 2) {
+ struct mqueue *q;
+
+ q = &OutputQueues[0];
+ logprintf("output from queue %d, normal has %d\n", i, q->qlen);
+ }
+ logprintf("Dequeue(%d): ", i);
+#endif
+ break;
+ }
+ i++;
+ }
+ }
+ if (modemout) {
+ nb = modemout->cnt;
+ if (nb > 300) nb = 300;
+ if (fd == 0) fd = 1;
+ nw = write(fd, MBUF_CTOP(modemout), nb);
+#ifdef QDEBUG
+ logprintf("wrote: %d(%d)\n", nw, nb);
+ LogDumpBuff(LOG_HDLC, "modem write", MBUF_CTOP(modemout), nb);
+#endif
+ if (nw > 0) {
+ modemout->cnt -= nw;
+ modemout->offset += nw;
+ if (modemout->cnt == 0) {
+ modemout = mbfree(modemout);
+#ifdef QDEBUG
+ logprintf(" mbfree\n");
+#endif
+ }
+ } else if (nw < 0)
+ perror("modem write");
+ }
+}
+
+int
+DialModem()
+{
+ char ScriptBuffer[200];
+
+ strcpy(ScriptBuffer, VarDialScript);
+ if (DoChat(ScriptBuffer) > 0) {
+ fprintf(stderr, "dial OK!\n");
+ strcpy(ScriptBuffer, VarLoginScript);
+ if (DoChat(ScriptBuffer) > 0) {
+ fprintf(stderr, "login OK!\n");
+ return(1);
+ } else {
+ fprintf(stderr, "login failed.\n");
+ }
+ ModemTimeout(); /* Dummy call to check modem status */
+ }
+ else
+ fprintf(stderr, "dial failed.\n");
+ return(0);
+}
+
+int
+ShowModemStatus()
+{
+ int nb;
+
+ printf("device: %s speed: %d\n", VarDevice, VarSpeed);
+ switch (VarParity & CSIZE) {
+ case CS7:
+ printf("cs7, ");
+ break;
+ case CS8:
+ printf("cs8, ");
+ break;
+ }
+ if (VarParity & PARENB) {
+ if (VarParity & PARODD)
+ printf("odd parity\n");
+ else
+ printf("even parity\n");
+ } else
+ printf("none parity\n");
+#ifdef DEBUG
+ printf("fd = %d, modem control = %o\n", modem, mbits);
+#endif
+ printf("connect count: %d\n", connect_count);
+ ioctl(modem, TIOCOUTQ, &nb);
+ printf("outq: %d\n", nb);
+ printf("DialScript = %s\n", VarDialScript);
+ printf("LoginScript = %s\n", VarLoginScript);
+ printf("PhoneNumber = %s\n", VarPhone);
+ return(1);
+}
diff --git a/usr.sbin/ppp/modem.h b/usr.sbin/ppp/modem.h
new file mode 100644
index 0000000..9670ab6
--- /dev/null
+++ b/usr.sbin/ppp/modem.h
@@ -0,0 +1,37 @@
+/*
+ * 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. 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:
+ */
+
+#ifndef _MODEM_H_
+#define _MODEM_H_
+
+extern int RawModem(int);
+extern void UnrawModem(int);
+extern void UpModem(int);
+extern void DownModem(int);
+extern void WriteModem(int, char *, int);
+extern void ModemStartOutput(int);
+extern int OpenModem(int);
+extern int ModemSpeed(void);
+extern int ModemQlen(void);
+extern int DialModem(void);
+
+#endif
diff --git a/usr.sbin/ppp/os.c b/usr.sbin/ppp/os.c
new file mode 100644
index 0000000..72da1c6
--- /dev/null
+++ b/usr.sbin/ppp/os.c
@@ -0,0 +1,341 @@
+/*
+ * PPP OS Layer Interface 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:
+ */
+#include "fsm.h"
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <net/route.h>
+#if __FreeBSD__ >= 2
+#include <osreldate.h>
+#endif
+#if defined(__NetBSD__) || _BSDI_VERSION >= 199312 || __FreeBSD_version >=199412
+#include <sys/select.h>
+#endif
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <net/if_tun.h>
+#include <errno.h>
+#include "ipcp.h"
+#include "os.h"
+
+static struct ifaliasreq ifra;
+static struct ifreq ifrq;
+static struct in_addr oldmine, oldhis;
+static int linkup;
+
+#ifdef bsdi
+extern char *inet_ntoa();
+#endif
+extern void HangupModem();
+
+char *IfDevName;
+
+static int
+SetIpDevice(myaddr, hisaddr, netmask, updown)
+struct in_addr myaddr, hisaddr, netmask;
+int updown;
+{
+ struct sockaddr_in *sin;
+ int s;
+ int changeaddr = 0;
+ u_long mask, addr;
+
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s < 0) {
+ perror("socket");
+ return(-1);
+ }
+
+ if (updown == 0) {
+ if (oldmine.s_addr == 0 && oldhis.s_addr == 0) {
+ return(0);
+ }
+ bzero(&ifra.ifra_addr, sizeof(ifra.ifra_addr));
+ bzero(&ifra.ifra_broadaddr, sizeof(ifra.ifra_addr));
+ bzero(&ifra.ifra_mask, sizeof(ifra.ifra_addr));
+#ifdef DEBUG
+ logprintf("DIFADDR\n");
+#endif
+ if (ioctl(s, SIOCDIFADDR, &ifra) < 0) {
+ perror("SIOCDIFADDR");
+ return(-1);
+ }
+
+ oldmine.s_addr = oldhis.s_addr = 0;
+ } else {
+ /*
+ * If given addresses are alreay set, then ignore this request.
+ */
+ if (oldmine.s_addr == myaddr.s_addr && oldhis.s_addr == hisaddr.s_addr)
+ return(0);
+ /*
+ * If different address has been set, then delete it first.
+ */
+ if (oldmine.s_addr || oldhis.s_addr) {
+ changeaddr = 1;
+ }
+ /*
+ * Set interface address
+ */
+ sin = (struct sockaddr_in *)&(ifra.ifra_addr);
+ sin->sin_family = AF_INET;
+ sin->sin_addr = oldmine = myaddr;
+ sin->sin_len = sizeof(*sin);
+ /*
+ * Set destination address
+ */
+ sin = (struct sockaddr_in *)&(ifra.ifra_broadaddr);
+ sin->sin_family = AF_INET;
+ sin->sin_addr = oldhis = hisaddr;
+ sin->sin_len = sizeof(*sin);
+ /*
+ */
+ addr = ntohl(myaddr.s_addr);
+ if (IN_CLASSA(addr))
+ mask = IN_CLASSA_NET;
+ else if (IN_CLASSB(addr))
+ mask = IN_CLASSB_NET;
+ else
+ mask = IN_CLASSC_NET;
+ /*
+ * if subnet mask is given, use it instead of class mask.
+ */
+ if (netmask.s_addr && (ntohl(netmask.s_addr) & mask) == mask)
+ mask = ntohl(netmask.s_addr);
+
+ sin = (struct sockaddr_in *)&(ifra.ifra_mask);
+ sin->sin_family = AF_INET;
+ sin->sin_addr.s_addr = htonl(mask);
+ sin->sin_len = sizeof(*sin);
+
+ if (changeaddr) {
+ /*
+ * Interface already exists. Just change the address.
+ */
+ bcopy(&ifra.ifra_addr, &ifrq.ifr_addr, sizeof(struct sockaddr));
+ if (ioctl(s, SIOCSIFADDR, &ifra) < 0)
+ perror("SIFADDR");;
+ bcopy(&ifra.ifra_broadaddr, &ifrq.ifr_dstaddr, sizeof(struct sockaddr));
+ if (ioctl(s, SIOCSIFDSTADDR, &ifrq) < 0)
+ perror("SIFDSTADDR");;
+#ifdef notdef
+ bcopy(&ifra.ifra_mask, &ifrq.ifr_broadaddr, sizeof(struct sockaddr));
+ if (ioctl(s, SIOCSIFBRDADDR, &ifrq) < 0)
+ perror("SIFBRDADDR");
+#endif
+ } else if (ioctl(s, SIOCAIFADDR, &ifra) < 0) {
+ perror("SIOCAIFADDR");
+ return(-1);
+ }
+ }
+ close(s);
+ return(0);
+}
+
+int
+OsSetIpaddress(myaddr, hisaddr, netmask)
+struct in_addr myaddr, hisaddr, netmask;
+{
+ return(SetIpDevice(myaddr, hisaddr, netmask, 1));
+}
+
+static struct in_addr peer_addr;
+struct in_addr defaddr;
+
+void
+OsLinkup()
+{
+ char *s;
+
+ if (linkup == 0) {
+ if (setuid(0) < 0)
+ logprintf("setuid failed\n");
+ peer_addr = IpcpInfo.his_ipaddr;
+ s = (char *)inet_ntoa(peer_addr);
+ LogPrintf(LOG_PHASE, "OsLinkup: %s\n", s);
+
+ if (SelectSystem(inet_ntoa(IpcpInfo.want_ipaddr), LINKFILE) < 0) {
+ if (dstsystem) {
+ if (SelectSystem(dstsystem, LINKFILE) < 0)
+ SelectSystem("MYADDR", LINKFILE);
+ } else
+ SelectSystem("MYADDR", LINKFILE);
+ }
+ linkup = 1;
+ }
+}
+
+void
+OsLinkdown()
+{
+ char *s;
+
+ if (linkup) {
+ s = (char *)inet_ntoa(peer_addr);
+ LogPrintf(LOG_PHASE, "OsLinkdown: %s\n", s);
+ if (!(mode & MODE_AUTO))
+ DeleteIfRoutes(0);
+ linkup = 0;
+ }
+}
+
+int
+OsInterfaceDown(final)
+int final;
+{
+ struct in_addr zeroaddr;
+ int s;
+
+ OsLinkdown();
+ if (!final && (mode & MODE_AUTO)) /* We still want interface alive */
+ return(0);
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s < 0) {
+ perror("socket");
+ return(-1);
+ }
+ ifrq.ifr_flags &= ~IFF_UP;
+ if (ioctl(s, SIOCSIFFLAGS, &ifrq) < 0) {
+ perror("SIOCSIFFLAGS");
+ close(s);
+ return(-1);
+ }
+
+ zeroaddr.s_addr = 0;
+ SetIpDevice(zeroaddr, zeroaddr, zeroaddr, 0);
+
+ close(s);
+ return(0);
+}
+
+void
+OsSetInterfaceParams(type, mtu, speed)
+int type, mtu, speed;
+{
+ struct tuninfo info;
+#if __FreeBSD__ >= 2
+ info.tif_type = type;
+ info.tif_mtu = mtu;
+ info.tif_baudrate = speed;
+#else
+ info.if_type = type;
+ info.if_mtu = mtu;
+ info.if_baudrate = speed;
+#endif
+ if (ioctl(tun_out, TUNSIFINFO, &info) < 0)
+ perror("TUNSIFINFO");
+}
+
+/*
+ * Open tunnel device and returns its descriptor
+ */
+int
+OpenTunnel(ptun)
+int *ptun;
+{
+ int s;
+ char *cp;
+ char *suffix = "0123456789";
+ char ifname[IFNAMSIZ];
+ char devname[12];
+
+ strcpy(devname, "/dev/tun0");
+ for (cp = suffix; *cp; cp++) {
+ devname[8] = *cp;
+ tun_out = open(devname, O_RDWR);
+ if (tun_out >= 0)
+ break;
+ }
+ *ptun = cp - suffix;
+ if (*cp == '\0') {
+ fprintf(stderr, "No tunnel device is available.\n");
+ return(-1);
+ }
+
+ /*
+ * At first, name the interface.
+ */
+ strcpy(ifname, devname + 5);
+
+ bzero((char *)&ifra, sizeof(ifra));
+ bzero((char *)&ifrq, sizeof(ifrq));
+
+ strncpy(ifrq.ifr_name, ifname, IFNAMSIZ);
+ strncpy(ifra.ifra_name, ifname, IFNAMSIZ);
+
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s < 0) {
+ perror("socket");
+ return(-1);
+ }
+
+ /*
+ * Now, bring up the interface.
+ */
+ if (ioctl(s, SIOCGIFFLAGS, &ifrq) < 0) {
+ perror("SIOCGIFFLAGS");
+ close(s);
+ return(-1);
+ }
+
+ ifrq.ifr_flags |= IFF_UP;
+ if (ioctl(s, SIOCSIFFLAGS, &ifrq) < 0) {
+ perror("SIOCSIFFLAGS");
+ close(s);
+ return(-1);
+ }
+
+ tun_in = tun_out;
+ IfDevName = devname + 5;
+ if (GetIfIndex(IfDevName) < 0) {
+ fprintf(stderr, "can't find ifindex.\n");
+ close(s);
+ return(-1);
+ }
+ printf("Using interface: %s\r\n", IfDevName);
+ LogPrintf(LOG_PHASE, "Using interface: %s\n", IfDevName);
+ close(s);
+ return(0);
+}
+
+void
+OsCloseLink(flag)
+int flag;
+{
+ HangupModem(flag);
+}
+
+void
+OsAddInOctets(cnt)
+int cnt;
+{
+}
+
+void
+OsAddOutOctets(cnt)
+int cnt;
+{
+}
+
diff --git a/usr.sbin/ppp/os.h b/usr.sbin/ppp/os.h
new file mode 100644
index 0000000..514b4a1
--- /dev/null
+++ b/usr.sbin/ppp/os.h
@@ -0,0 +1,34 @@
+/*
+ * 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. 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:
+ */
+
+#ifndef _OS_H_
+#define _OS_H_
+
+int OsSetIpaddress(struct in_addr myaddr, struct in_addr hisaddr, struct in_addr netmask);
+int OsInterfaceDown(int);
+void OsSetInterfaceParams(int type, int mtu, int speed);
+int OpenTunnel(int *);
+void OsCloseLink(int flag);
+void OsLinkup(void), OsLinkdown(void);
+void OsSetRoute();
+void DeleteIfRoutes(int);
+#endif
diff --git a/usr.sbin/ppp/pap.c b/usr.sbin/ppp/pap.c
new file mode 100644
index 0000000..3aaa25a
--- /dev/null
+++ b/usr.sbin/ppp/pap.c
@@ -0,0 +1,163 @@
+/*
+ * PPP PAP Module
+ *
+ * Written by Toshiharu OHNO (tony-o@iij.ad.jp)
+ *
+ * Copyright (C) 1993-94, 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 Imprement retransmission timer.
+ */
+#include "fsm.h"
+#include "lcp.h"
+#include "pap.h"
+#include "vars.h"
+#include "hdlc.h"
+#include "lcpproto.h"
+#include "phase.h"
+
+static char *papcodes[] = {
+ "???", "REQUEST", "ACK", "NAK"
+};
+
+static int papid;
+
+void
+SendPapChallenge()
+{
+ struct fsmheader lh;
+ struct mbuf *bp;
+ u_char *cp;
+ int namelen, keylen, plen;
+
+ namelen = strlen(VarAuthName);
+ keylen = strlen(VarAuthKey);
+ plen = namelen + keylen + 2;
+#ifdef DEBUG
+ logprintf("namelen = %d, keylen = %d\n", namelen, keylen);
+ LogPrintf(LOG_PHASE, "PAP: %s (%s)\n", VarAuthName, VarAuthKey);
+#endif
+ lh.code = PAP_REQUEST;
+ lh.id = ++papid;
+ lh.length = htons(plen + sizeof(struct fsmheader));
+ bp = mballoc(plen + sizeof(struct fsmheader), MB_FSM);
+ bcopy(&lh, MBUF_CTOP(bp), sizeof(struct fsmheader));
+ cp = MBUF_CTOP(bp) + sizeof(struct fsmheader);
+ *cp++ = namelen;
+ bcopy(VarAuthName, cp, namelen);
+ cp += namelen;
+ *cp++ = keylen;
+ bcopy(VarAuthKey, cp, keylen);
+
+ HdlcOutput(PRI_NORMAL, PROTO_PAP, bp);
+}
+
+static void
+SendPapCode(id, code, message)
+int id;
+char *message;
+int code;
+{
+ struct fsmheader lh;
+ struct mbuf *bp;
+ u_char *cp;
+ int plen, mlen;
+
+ lh.code = code;
+ lh.id = id;
+ mlen = strlen(message);
+ plen = mlen + 1;
+ lh.length = htons(plen + sizeof(struct fsmheader));
+ bp = mballoc(plen + sizeof(struct fsmheader), MB_FSM);
+ bcopy(&lh, MBUF_CTOP(bp), sizeof(struct fsmheader));
+ cp = MBUF_CTOP(bp) + sizeof(struct fsmheader);
+ *cp++ = mlen;
+ bcopy(message, cp, mlen);
+ LogPrintf(LOG_PHASE, "PapOutput: %s\n", papcodes[code]);
+ HdlcOutput(PRI_NORMAL, PROTO_PAP, bp);
+}
+
+/*
+ * Validate given username and passwrd against with secret table
+ */
+static int
+PapValidate(name, key)
+u_char *name, *key;
+{
+ int nlen, klen;
+
+ nlen = *name++;
+ klen = *key;
+ *key++ = 0;
+ key[klen] = 0;
+ logprintf("name: %s (%d), key: %s (%d)\n", name, nlen, key, klen);
+ return(AuthValidate(SECRETFILE, name, key));
+}
+
+void
+PapInput(bp)
+struct mbuf *bp;
+{
+ int len = plength(bp);
+ struct fsmheader *php;
+ struct lcpstate *lcp = &LcpInfo;
+ u_char *cp;
+
+ if (len >= sizeof(struct fsmheader)) {
+ php = (struct fsmheader *)MBUF_CTOP(bp);
+ if (len >= ntohs(php->length)) {
+ if (php->code < PAP_REQUEST || php->code > PAP_NAK)
+ php->code = 0;
+ LogPrintf(LOG_PHASE, "PapInput: %s\n", papcodes[php->code]);
+
+ switch (php->code) {
+ case PAP_REQUEST:
+ cp = (u_char *) (php + 1);
+ if (PapValidate(cp, cp + *cp + 1)) {
+ SendPapCode(php->id, PAP_ACK, "Greetings!!");
+ lcp->auth_ineed = 0;
+ if (lcp->auth_iwait == 0)
+ NewPhase(PHASE_NETWORK);
+ } else {
+ SendPapCode(php->id, PAP_NAK, "Login incorrect");
+ LcpClose();
+ }
+ break;
+ case PAP_ACK:
+ cp = (u_char *)(php + 1);
+ len = *cp++;
+ cp[len] = 0;
+ LogPrintf(LOG_PHASE, "Received PAP_ACK (%s)\n", cp);
+ if (lcp->auth_iwait == PROTO_PAP) {
+ lcp->auth_iwait = 0;
+ if (lcp->auth_ineed == 0)
+ NewPhase(PHASE_NETWORK);
+ }
+ break;
+ case PAP_NAK:
+ cp = (u_char *)(php + 1);
+ len = *cp++;
+ cp[len] = 0;
+ LogPrintf(LOG_PHASE, "Received PAP_NAK (%s)\n", cp);
+ LcpClose();
+ break;
+ }
+ }
+ }
+ pfree(bp);
+}
diff --git a/usr.sbin/ppp/pap.h b/usr.sbin/ppp/pap.h
new file mode 100644
index 0000000..14ca50c
--- /dev/null
+++ b/usr.sbin/ppp/pap.h
@@ -0,0 +1,29 @@
+/*
+ * 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. 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:
+ */
+
+#ifndef _PAP_H_
+#define _PAP_H_
+
+#define PAP_REQUEST 1
+#define PAP_ACK 2
+#define PAP_NAK 3
+#endif
diff --git a/usr.sbin/ppp/pathnames.h b/usr.sbin/ppp/pathnames.h
new file mode 100644
index 0000000..de3c339
--- /dev/null
+++ b/usr.sbin/ppp/pathnames.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)pathnames.h 5.2 (Berkeley) 6/1/90
+ *
+ * $Id:$
+ */
+
+#include <paths.h>
+
+#define _PATH_ACULOG "/var/log/aculog"
+#if defined (__FreeBSD__)
+#define _PATH_LOCKDIRNAME "/var/spool/lock/LCK..%s"
+#else
+#define _PATH_LOCKDIRNAME "/var/spool/uucp/LCK..%s"
+#endif
+#ifdef notdef
+#define _PATH_LOCKDIRNAME "/var/spool/uucp/LCK/LCK..%s"
+#endif
+#define _PATH_PHONES "/etc/phones"
+#define _PATH_REMOTE "/etc/remote"
diff --git a/usr.sbin/ppp/phase.h b/usr.sbin/ppp/phase.h
new file mode 100644
index 0000000..d6314fe
--- /dev/null
+++ b/usr.sbin/ppp/phase.h
@@ -0,0 +1,36 @@
+/*
+ * 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. 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:
+ */
+
+#ifndef _PHASE_H_
+#define _PHASE_H_
+
+#define PHASE_DEAD 0 /* Link is dead */
+#define PHASE_ESTABLISH 1 /* Establishing link */
+#define PHASE_AUTHENTICATE 2 /* Beeing authenticate */
+#define PHASE_NETWORK 3
+#define PHASE_TERMINATE 4 /* Terminating link */
+
+int phase; /* Curent phase */
+
+extern void NewPhase(int);
+extern char *PhaseNames[];
+#endif
diff --git a/usr.sbin/ppp/ppp.8 b/usr.sbin/ppp/ppp.8
new file mode 100644
index 0000000..b46eed1
--- /dev/null
+++ b/usr.sbin/ppp/ppp.8
@@ -0,0 +1,492 @@
+.\" manual page [] for ppp 0.93
+.\" $Id:$
+.\" SH section heading
+.\" SS subsection heading
+.\" LP paragraph
+.\" IP indented paragraph
+.\" TP hanging label
+.TH PPP 8
+.SH NAME
+ppp \- Point to Point Protocol (aka iijppp)
+.SH SYNOPSIS
+.B ppp
+[
+.I -auto | -direct -dedicated
+] [
+.I system
+]
+.SH DESCRIPTION
+.LP
+ This is user process \fIPPP\fR software package. Normally, \fIPPP\fR is implemented as a part of kernel and hard to debug and/or modify its behavior. However, in this implementation, \fIPPP\fR is implemented as a user process with the help of tunnel device driver.
+.LP
+
+.SH Major Features
+
+.TP 2
+o
+Provide interactive user interface. Using its command mode, user can easily enter commands to establish the connection with the peer, check the status of connection, and close the connection.
+
+.TP 2
+o
+Supports both of manual and automatic dialing. Interactive mode has ``term'' command which enables you to talk to your modem directory. When your modem is connected to the peer, and it starts to speak \fIPPP\fR, \fIPPP\fR software detects it and turns into packet mode automatically. Once you have convinced how to connect with the peer, you can write chat script to define necessary dialing and login procedure for later convenience.
+.TP 2
+o
+Supports on-demand dialup capability. By using auto mode, \fIPPP\fR program will act as a daemon and wait for the packet send to the peer. Once packet is found, daemon automatically dials and establish the connection.
+
+.TP 2
+o
+Can act as server which accept incoming \fIPPP\fR connection.
+
+.TP 2
+o
+Supports PAP and CHAP authentification.
+
+.TP 2
+o
+Supports packet filtering. User can define three kinds of filters; ifilter for incoming packet, ofilter for outgoing packet and dfilter to define dialing trigger packet.
+
+.TP 2
+o
+Tunnel driver supports bpf. That is, user can use tcpdump to check packet flow over the \fIPPP\fR link.
+
+.TP 2
+o
+Supports \fIPPP\fR over TCP capability.
+
+.TP 2
+o
+Supports IETF draft Predictor-1 compression.
+
+.TP 2
+o
+Runs under BSDI-1.1 and FreeBSD-1.1. Patch for NeXTSTEP 3.2 is also available on the net.
+
+.SH MANUAL DIALING
+.LP
+
+ % ppp
+ User Process PPP written by Toshiharu OHNO.
+ -- You can specify modem and device name using following commands.
+ ppp> set line /dev/cua01
+ ppp> set speed 38400
+ ppp> set parity even
+ ppp> show modem
+ -- Modem related parameters are shown in here
+ ppp>
+ -- Use term command to talk with your modem
+ ppp> term
+ at
+ OK
+ atdt123456
+ CONNECT
+
+ login: ppp
+ Password:
+ -- PPP started in remote side ---
+
+ -- When peer start to speak PPP, the program will detect it
+ -- automatically and back to command mode.
+ ppp>
+ \fBPPP\fR>
+
+ -- NOW, you are get connected !! Note that prompt has changed to
+ -- capital letters
+ PPP> show lcp
+
+ -- You'll see LCP status --
+
+ PPP> show ipcp
+
+ -- You'll see IPCP status --
+ -- At this point, your machine has host route to the peer.
+ -- If your want to add default route entry, then enter
+
+ PPP> add 0 0 HISADDR
+
+ -- Here string `HISADDR' represents IP address of connected peer.
+
+ PPP>
+ -- Use applications (i.e. ping, telnet, ftp) in other windows
+
+ PPP> show log
+
+ -- Gives you some logging messages
+
+ PPP> close
+
+ -- Connection is closed, and modem will be hanged.
+
+ ppp> quit
+ %
+.LP
+.SH AUTOMATIC DIALING
+
+.LP
+To use automatic dialing, you must prepare Dial and Login chat script.See example definition found in ppp.conf.sample(Format of ppp.conf is pretty simple.)
+.LP
+
+.TP 2
+o
+Each line contains one command, label or comment.
+
+.TP 2
+o
+Line stating with # is treated as a comment line.
+
+.TP 2
+o
+Label name has to start from first column and should be followed by colon (:).
+
+.TP 2
+o
+Command line must contains space or tab at first column.
+
+.LP
+If ppp.conf is ready, specify destination label name when you invoke ppp. Commands associated with destination label is executed when ppp command is invoked. Note that commands associated with ``default'' label is ALWAYS executed.
+
+Once connection is made, you'll find that prompt is changed to
+
+ capital \fIPPP\fR>.
+
+ % ppp pm2
+ ...
+ ppp> dial
+ dial OK!
+ login OK!
+ PPP>
+
+If ppp.linkup file is available, its contents are executed when \fIPPP\fR link is connected. See example which add default route. The string HISADDR matches with IP address of connected peer.
+.LP
+
+.SH DAIL ON DEMAND
+
+.LP
+ To play with demand dialing, you must use -auto option. Also, you must specify destination label with proper setup in ppp.conf. It must contain ``ifaddr'' command to define peer's IP address. (refer /etc/ppp/ppp.conf.sample)
+.LP
+
+ % ppp -auto pm2demand
+ ...
+ %
+
+.LP
+When -auto is specified, \fIPPP\fR program works as a daemon. But, you are still able to use command features to check its behavior.
+.LP
+
+ % telnet localhost 3000
+ ...
+ PPP> show ipcp
+ ....
+
+.LP
+ Each ppp has associated port number, which is computed as "3000 + tunnel_device_number". If 3000 is not good base number, edit defs.h. When packet toward to remote network is detected, \fIPPP\fR will take dialing action and try to connect with the peer. If dialing is failed, program will wait for 30 seconds. Once this hold time expired, another trigger packet cause dialing action. Note that automatic re-dialing is NOT implemented.
+.LP
+
+ To terminate program, use
+
+ PPP> close
+ \fBppp\fR> quit all
+
+.LP
+ Simple ``quit'' command will terminates telnet connection, but \fIPPP\fR program itself is not terminated. You must use ``quit all'' to terminate the program running as daemon.
+.LP
+
+.SH PACKET FILTERING
+
+.LP
+This implementation supports packet filtering. There are three filters; ifilter, ofilter and dfilter. Here's some basics.
+.LP
+
+.TP 2
+o
+Filter definition has next syntax.
+
+ set filter-name rule-no action [src_addr/src_width] [dst_addr/dst_width]
+ [proto [src [lt|eq|gt] port ] [dst [lt|eq|gt] port] [estab]
+
+ a) filter-name should be ifilter, ofilter or dfiler.
+
+ b) There are two actions permit and deny. If given packet is matched
+ against the rule, action is taken immediately.
+
+ c) src_width and dst_width works like a netmask to represent address range.
+
+ d) proto must be one of icmp, udp or tcp.
+
+.TP 2
+o
+Each filter can hold upto 20 rules. Rule number starts from 0. Entire rule set is not effective until rule 0 is defined.
+
+.TP 2
+o
+If no rule is matched with a packet, that packet will be discarded (blocked).
+
+.TP 2
+o
+Use ``set filer-name -1'' to flush all rules.
+
+.LP
+ See /etc/ppp/ppp.conf.filter.example
+.LP
+
+.SH RECEIVE INCOMING PPP CONNECTION
+
+.LP
+ To receive incoming \fIPPP\fR connection request, follow next steps.
+.LP
+
+ a) Prepare bidir entry in your /etc/gettytab
+
+ bidir.38400:\
+ :bi:ap:hf:tc=38400-baud:
+
+ b) Edit /etc/ttys to enable getty on the port where modem is attached.
+
+ cua00 "/usr/libexec/getty stdir.38400" dialup on
+
+ Don't forget to send HUP signal to init process.
+
+ # kill -HUP 1
+
+ c) Prepare account for incoming user.
+
+ppp:*:21:0:PPP Login User:/home/ppp:/usr/local/bin/ppplogin
+
+ d) Create /usr/local/bin/ppplogin file with next contents.
+
+ #!/bin/sh
+ /usr/local/bin/ppp -direct
+
+ You can specify label name for further control.
+
+.LP
+ Direct mode (-direct) lets \fIPPP\fR to work with standard in and out. Again, you can telnet to 3000 to get command mode control.
+.LP
+
+.SH SETTING IDLE TIMER
+
+.LP
+ To check/set idletimer, use ``show timeout'' and ``set timeout'' command.
+.LP
+
+ Ex. ppp> set timeout 600
+
+.LP
+ Timeout period is measured in secs and default value is 180 or 3 min. To disable idle timer function, use ``set timeout 0''.
+.LP
+
+.LP
+ In -auto mode, idle timeout cause \fIPPP\fR session closed. However, \fIPPP\fR program itself is keep running. Another trigger packet cause dialing action.
+.LP
+
+.SH Predictor-1 compression
+
+.LP
+ This version supports CCP and Predictor type 1 compression based on current IETF-draft specs. As a default behavior, \fIPPP\fR will propose to use (or willing to accept) this capability and use it if peer agrees (or requests).
+.LP
+
+.LP
+ To disable CCP/predictor function completely, use ``disable pred'' and ``deny pred'' command.
+.LP
+
+.SH Controlling IP address
+
+.LP
+ \fIPPP\fR uses IPCP to negotiate IP addresses. Each side of node informs IP address that willing to use to the peer, and if requested IP address is acceptable, \fIPPP\fR returns ACK to requester. Otherwise, \fIPPP\fR returns NAK to suggest the peer to use different IP address. When both side of nodes agrees to accept the received request (and send ACK), IPCP is reached to open state and network level connection is established.
+.LP
+
+.LP
+ To control, this IPCP behavior, this implementation has ``set ifaddr'' to define MY and HIS IP address.
+.LP
+
+.TP3
+ifaddr src_addr dst_addr
+
+.LP
+ Where, src_addr is the IP address that my side is willing to use, and dst_addr is the IP address which his side should use.
+.LP
+
+.TP3
+ifaddr 192.244.177.38 192.244.177.2
+
+For example, above specification means
+
+.TP
+o
+I strongly want to use 192.244.177.38 as my side. I'll disagree when peer suggest me to use other addresses.
+
+.TP 2
+o
+I strongly insists peer to use 192.244.177.2 as his side address. I don't permit him to use any IP address but 192.244.177.2. When peer request other IP address, I always suggest him to use 192.244.177.2.
+
+.LP
+ This is all right, when each side has pre-determined IP address.
+However, it is often the case one side is acting as a server which
+controls IP address and the other side should obey the direction from him.
+In order to allow more flexible behavior, `ifaddr' command allows user to specify IP address more loosely.
+.LP
+
+.TP 2
+ifaddr 192.244.177.38/24 192.244.177.2/20
+
+ Number followed by slash (/) represents number of bits significant in IP address. That is, this example means
+
+.TP 2
+o
+I'd like to use 192.244.177.38 as my side address, if it is possible. But I also accept any IP address between 192.244.177.0 and 192.244.177.255.
+
+.TP 2
+o
+I'd like to make him to use 192.244.177.2 as his side address. But I also permit him to use any IP address between 192.244.176.0 and 192.244.191.255.
+
+ Notes:
+
+.TP 2
+o
+As you may have already noticed, 192.244.177.2 is equivalent to say 192.244.177.2/32.
+
+.TP 2
+o
+As an exception, 0 is equivalent to 0.0.0.0/0. Means, I have no idea about IP address and obey what he says.
+
+.TP 2
+o
+192.244.177.2/0 means that I'll accept/permit any IP address but I'll try to insist to use 192.244.177.2 at first.
+
+.SH Connecting with service provider
+
+.LP
+ 1) Describe provider's phone number in DialScript. Use ``set dial'' or
+ ``set phone'' command.
+
+ 2) Describle login procedure in LoginScript. Use ``set login'' command.
+
+.TP
+3) Use ``set ifaddr'' command to define IP address.
+
+ o If you know what IP address provider uses, then use it as his address.
+
+ o If provider has assigned particular IP address for you, then use it
+ as my address.
+
+ o If provider assigns your address dynamically, use 0 as my address.
+
+ o If you have no info on IP addresses, then try
+
+ set ifaddr 0 0
+.TP 2
+4) If provider request you to use PAP/CHAP auth method,
+add next lines into your ppp.conf.
+
+.TP 3
+.B enable pap (or enable chap)
+.TP 3
+.B disable chap (or disable pap)
+.TP 3
+.B set authname MyName
+.TP 3
+.B set authkey MyPassword
+.TP 3
+
+.LP
+Please refer /etc/ppp/example/ppp.conf.iij for some real examples.
+.LP
+
+.SH Logging facility
+
+.LP
+ \fI\fIPPP\fR\fR is able to generate following level log info as /var/log/ppp.log
+.LP
+
+.TP
+.B Phase
+Phase transition log output
+.TP
+.B Chat
+Generate Chat script trace log
+.TP
+.B LQM
+Generate LQR report
+.TP
+.B LCP
+Generate LCP/IPCP packet trace
+.TP
+.B TCP/IP
+Dump TCP/IP packet
+.TP
+HDLC
+Dump HDLC packet in hex
+.TP
+.B Async
+Dump async level packet in hex
+
+.LP
+ ``set debug'' command allows you to set logging output level,
+and multiple levels can be specified.
+Default is equivalent to ``set debug phase lcp''.
+
+.SH For more details
+
+.TP 2
+o
+Please read Japanese doc for complete explanation.
+Well, it is not useful for non-japanese readers,
+but examples in the document may help you to guess.
+
+.TP 2
+o
+Please read example configuration files.
+
+.TP 2
+o
+Use ``help'', ``show ?'' and ``set ?'' command.
+
+.TP 2
+o
+NetBSD and BSDI-1.0 has been supported in previous release,
+but no longer supported in this release.
+Please contact to author if you need old driver code.
+
+.SH FILES
+.LP
+\fIPPP\fR may refers three files, ppp.conf, ppp.linkup and ppp.secret.
+These files are placed in /etc/ppp,
+but user can create his own files under HOME directory as .ppp.conf,
+.ppp.linkup and .ppp.secret.
+the ppp always try to consult to user's personal setup first.
+
+.TP
+.B $HOME/ppp/.ppp.[linkup|secret]
+User depend configuration files.
+
+.TP
+.B /etc/ppp/ppp.conf
+System default configuration file.
+
+.TP
+.B /etc/ppp/ppp.secret
+A authorization file for each system.
+
+.TP
+.B /etc/ppp/ppp.linkup
+A checking file when
+.I ppp
+establishes network level connection.
+
+.TP
+.B /var/log/ppp.log
+Logging and debug information file.
+
+.TP
+.B /var/spool/lock/Lck..*
+tty port locking file.
+
+.SH BUGS
+A Proxy arp is not support, yet.
+The TTS is little bit longer than pppd2.1, it's under improving ;-)
+
+.SH HISTORY
+This programm has deliverd into core since FreeBSD-2.1
+by Atsushi Murai (amurai@spec.co.jp).
+
+.SH AUTHORS
+Toshiharu OHNO (tony-o@iij.ad.jp)
diff --git a/usr.sbin/ppp/pred.c b/usr.sbin/ppp/pred.c
new file mode 100644
index 0000000..3f7bd11
--- /dev/null
+++ b/usr.sbin/ppp/pred.c
@@ -0,0 +1,237 @@
+/*
+ * 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. 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:
+ */
+
+#include "fsm.h"
+#include "hdlc.h"
+#include "lcpproto.h"
+#include "ccp.h"
+
+/*
+ * pred.c -- Test program for Dave Rand's rendition of the
+ * predictor algorithm
+ * Updated by: iand@labtam.labtam.oz.au (Ian Donaldson)
+ * Updated by: Carsten Bormann <cabo@cs.tu-berlin.de>
+ * Original : Dave Rand <dlr@bungi.com>/<dave_rand@novell.com>
+ */
+
+/* The following hash code is the heart of the algorithm:
+ * It builds a sliding hash sum of the previous 3-and-a-bit characters
+ * which will be used to index the guess table.
+ * A better hash function would result in additional compression,
+ * at the expense of time.
+ */
+#define IHASH(x) iHash = (iHash << 4) ^ (x)
+#define OHASH(x) oHash = (oHash << 4) ^ (x)
+
+static unsigned short int iHash, oHash;
+static unsigned char InputGuessTable[65536];
+static unsigned char OutputGuessTable[65536];
+
+static int
+compress(source, dest, len)
+unsigned char *source, *dest;
+int len;
+{
+ int i, bitmask;
+ unsigned char *flagdest, flags, *orgdest;
+
+ orgdest = dest;
+ while (len) {
+ flagdest = dest++; flags = 0; /* All guess wrong initially */
+ for (bitmask=1, i=0; i < 8 && len; i++, bitmask <<= 1) {
+ if (OutputGuessTable[oHash] == *source) {
+ flags |= bitmask; /* Guess was right - don't output */
+ } else {
+ OutputGuessTable[oHash] = *source;
+ *dest++ = *source; /* Guess wrong, output char */
+ }
+ OHASH(*source++);len--;
+ }
+ *flagdest = flags;
+ }
+ return(dest - orgdest);
+}
+
+static void
+SyncTable(source, dest, len)
+unsigned char *source, *dest;
+int len;
+{
+ int i;
+
+ while (len--) {
+ if (InputGuessTable[iHash] != *source) {
+ InputGuessTable[iHash] = *source;
+ }
+ IHASH(*dest++ = *source++);
+ }
+}
+
+static int
+decompress(source, dest, len)
+unsigned char *source, *dest;
+int len;
+{
+ int i, bitmask;
+ unsigned char flags, *orgdest;
+
+ orgdest = dest;
+ while (len) {
+ flags = *source++;
+ len--;
+ for (i=0, bitmask = 1; i < 8; i++, bitmask <<= 1) {
+ if (flags & bitmask) {
+ *dest = InputGuessTable[iHash]; /* Guess correct */
+ } else {
+ if (!len)
+ break; /* we seem to be really done -- cabo */
+ InputGuessTable[iHash] = *source; /* Guess wrong */
+ *dest = *source++; /* Read from source */
+ len--;
+ }
+ IHASH(*dest++);
+ }
+ }
+ return(dest - orgdest);
+}
+
+#define SIZ1 2048
+
+void
+Pred1Init(direction)
+int direction;
+{
+ if (direction & 1) { /* Input part */
+ iHash = 0;
+ bzero(InputGuessTable, sizeof(InputGuessTable));
+ }
+ if (direction & 2) { /* Output part */
+ oHash = 0;
+ bzero(OutputGuessTable, sizeof(OutputGuessTable));
+ }
+}
+
+void
+Pred1Output(pri, proto, bp)
+int pri;
+u_short proto;
+struct mbuf *bp;
+{
+ struct mbuf *mwp;
+ u_char *cp, *wp, *hp;
+ int orglen, len;
+ u_char bufp[SIZ1];
+ u_short fcs;
+
+ orglen = plength(bp) + 2; /* add count of proto */
+ mwp = mballoc((orglen+2)/8*9+12, MB_HDLCOUT);
+ hp = wp = MBUF_CTOP(mwp);
+ cp = bufp;
+ *wp++ = *cp++ = orglen >> 8;
+ *wp++ = *cp++ = orglen & 0377;
+ *cp++ = proto >> 8;
+ *cp++ = proto & 0377;
+ mbread(bp, cp, orglen-2);
+ fcs = HdlcFcs(INITFCS, bufp, 2+orglen);
+ fcs = ~fcs;
+
+ len = compress(bufp + 2, wp, orglen);
+#ifdef DEBUG
+ logprintf("orglen (%d) --> len (%d)\n", orglen, len);
+#endif
+ CcpInfo.orgout += orglen;
+ if (len < orglen) {
+ *hp |= 0x80;
+ wp += len;
+ CcpInfo.compout += len;
+ } else {
+ bcopy(bufp+2, wp, orglen);
+ wp += orglen;
+ CcpInfo.compout += orglen;
+ }
+
+ *wp++ = fcs & 0377;
+ *wp++ = fcs >> 8;
+ mwp->cnt = wp - MBUF_CTOP(mwp);
+ HdlcOutput(pri, PROTO_COMPD, mwp);
+}
+
+void
+Pred1Input(bp)
+struct mbuf *bp;
+{
+ u_char *cp, *pp;
+ int len, olen, len1;
+ struct mbuf *wp;
+ u_char *bufp;
+ u_short fcs, proto;
+
+ wp = mballoc(SIZ1, MB_IPIN);
+ cp = MBUF_CTOP(bp);
+ olen = plength(bp);
+ pp = bufp = MBUF_CTOP(wp);
+ *pp++ = *cp & 0177;
+ len = *cp++ << 8;
+ *pp++ = *cp;
+ len += *cp++;
+ CcpInfo.orgin += len & 0x7fff;
+ if (len & 0x8000) {
+ len1 = decompress(cp, pp, olen - 4);
+ CcpInfo.compin += olen;
+ len &= 0x7fff;
+ if (len != len1) { /* Error is detected. Send reset request */
+ CcpSendResetReq(&CcpFsm);
+ pfree(bp);
+ return;
+ }
+ cp += olen - 4;
+ pp += len1;
+ } else {
+ CcpInfo.compin += len;
+ SyncTable(cp, pp, len);
+ cp += len;
+ pp += len;
+ }
+ *pp++ = *cp++; /* CRC */
+ *pp++ = *cp++;
+ fcs = HdlcFcs(INITFCS, bufp, wp->cnt = pp - bufp);
+#ifdef DEBUG
+ logprintf("fcs = %04x (%s), len = %x, olen = %x\n",
+ fcs, (fcs == GOODFCS)? "good" : "bad", len, olen);
+#endif
+ if (fcs == GOODFCS) {
+ wp->offset += 2; /* skip length */
+ wp->cnt -= 4; /* skip length & CRC */
+ pp = MBUF_CTOP(wp);
+ proto = *pp++;
+ if (proto & 1) {
+ wp->offset++;
+ wp->cnt--;
+ } else {
+ wp->offset += 2;
+ wp->cnt -= 2;
+ proto = (proto << 8) | *pp++;
+ }
+ DecodePacket(proto, wp);
+ }
+ pfree(bp);
+}
diff --git a/usr.sbin/ppp/route.c b/usr.sbin/ppp/route.c
new file mode 100644
index 0000000..bf2cc09
--- /dev/null
+++ b/usr.sbin/ppp/route.c
@@ -0,0 +1,392 @@
+/*
+ * PPP Routing related Module
+ *
+ * Written by Toshiharu OHNO (tony-o@iij.ad.jp)
+ *
+ * Copyright (C) 1994, 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:$
+ */
+#include <sys/types.h>
+#include <machine/endian.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <net/route.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <errno.h>
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#if __FreeBSD__ >= 2
+#include <osreldate.h>
+#include <sys/sysctl.h>
+#else
+#include <sys/kinfo.h>
+#endif
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+static int IfIndex;
+
+struct rtmsg {
+ struct rt_msghdr m_rtm;
+ char m_space[64];
+};
+
+static int seqno;
+
+void
+OsSetRoute(cmd, dst, gateway, mask)
+int cmd;
+struct in_addr dst;
+struct in_addr gateway;
+struct in_addr mask;
+{
+ struct rtmsg rtmes;
+ int s, nb, wb;
+ char *cp;
+ u_long *lp;
+ struct sockaddr_in rtdata;
+
+ s = socket(PF_ROUTE, SOCK_RAW, 0);
+ if (s < 0)
+ logprintf("socket\n");
+
+ bzero(&rtmes, sizeof(rtmes));
+ rtmes.m_rtm.rtm_version = RTM_VERSION;
+ rtmes.m_rtm.rtm_type = cmd;
+ rtmes.m_rtm.rtm_addrs = RTA_DST | RTA_NETMASK;
+ if (cmd == RTM_ADD) rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY;
+ rtmes.m_rtm.rtm_seq = ++seqno;
+ rtmes.m_rtm.rtm_pid = getpid();
+ rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY;
+
+ bzero(&rtdata, sizeof(rtdata));
+ rtdata.sin_len = 16;
+ rtdata.sin_family = AF_INET;
+ rtdata.sin_port = 0;
+ rtdata.sin_addr = dst;
+
+ cp = rtmes.m_space;
+ bcopy(&rtdata, cp, 16);
+ cp += 16;
+ if (gateway.s_addr) {
+ rtdata.sin_addr = gateway;
+ bcopy(&rtdata, cp, 16);
+ cp += 16;
+ }
+
+ if (dst.s_addr == INADDR_ANY)
+ mask.s_addr = INADDR_ANY;
+
+ lp = (u_long *)cp;
+
+ if (mask.s_addr) {
+ *lp++ = 8;
+ cp += sizeof(int);
+ *lp = mask.s_addr;
+ } else
+ *lp = 0;
+ cp += sizeof(u_long);
+
+ nb = cp - (char *)&rtmes;
+ rtmes.m_rtm.rtm_msglen = nb;
+ wb = write(s, &rtmes, nb);
+ if (wb < 0) {
+ perror("write");
+ }
+#ifdef DEBUG
+ logprintf("wrote %d: dst = %x, gateway = %x\n", nb, dst.s_addr, gateway.s_addr);
+#endif
+ close(s);
+}
+
+static void
+p_sockaddr(sa, width)
+struct sockaddr *sa;
+int width;
+{
+ register char *cp;
+ register struct sockaddr_in *sin = (struct sockaddr_in *)sa;
+
+ cp = (sin->sin_addr.s_addr == 0) ? "default" :
+ inet_ntoa(sin->sin_addr);
+ printf("%-*.*s ", width, width, cp);
+}
+
+struct bits {
+ short b_mask;
+ char b_val;
+} bits[] = {
+ { RTF_UP, 'U' },
+ { RTF_GATEWAY, 'G' },
+ { RTF_HOST, 'H' },
+ { RTF_DYNAMIC, 'D' },
+ { RTF_MODIFIED, 'M' },
+ { RTF_CLONING, 'C' },
+ { RTF_XRESOLVE, 'X' },
+ { RTF_LLINFO, 'L' },
+ { RTF_REJECT, 'R' },
+ { 0 }
+};
+
+static void
+p_flags(f, format)
+register int f;
+char *format;
+{
+ char name[33], *flags;
+ register struct bits *p = bits;
+
+ for (flags = name; p->b_mask; p++)
+ if (p->b_mask & f)
+ *flags++ = p->b_val;
+ *flags = '\0';
+ printf(format, name);
+}
+
+int
+ShowRoute()
+{
+ struct rt_msghdr *rtm;
+ struct sockaddr *sa;
+ char *sp, *ep, *cp;
+ u_char *wp;
+ int *lp;
+ int needed, nb;
+ u_long mask;
+#if ( __FreeBSD_version >= 199412 )
+ int mib[6];
+#endif
+
+#if ( __FreeBSD_version >= 199412 )
+ mib[0] = CTL_NET;
+ mib[1] = PF_ROUTE;
+ mib[2] = 0; /* protocol */
+ mib[3] = 0; /* wildcard address family */
+ mib[4] = NET_RT_DUMP;
+ mib[5] = 0; /* no flags */
+ needed = sysctl(mib, 6, NULL, &needed, NULL, 0 );
+#else
+ needed = getkerninfo(KINFO_RT_DUMP, 0, 0, 0);
+#endif
+ if (needed < 0)
+ return(1);
+ sp = malloc(needed);
+ if (sp == NULL)
+ return(1);
+#if ( __FreeBSD_version >= 199412 )
+ if (sysctl(mib, 6, sp, &needed, NULL, 0 ) < 0)
+ return(1);
+#else
+ if (getkerninfo(KINFO_RT_DUMP, sp, &needed, 0) < 0)
+ return(1);
+#endif
+ ep = sp + needed;
+
+ for (cp = sp; cp < ep; cp += rtm->rtm_msglen) {
+ rtm = (struct rt_msghdr *)cp;
+ sa = (struct sockaddr *)(rtm + 1);
+ mask = 0xffffffff;
+ if (rtm->rtm_addrs == RTA_DST)
+ p_sockaddr(sa, 36);
+ else {
+ wp = (u_char *)cp + rtm->rtm_msglen;
+ p_sockaddr(sa, 16);
+ if (sa->sa_len == 0)
+ sa->sa_len = sizeof(long);
+ sa = (struct sockaddr *)(sa->sa_len + (char *)sa);
+ p_sockaddr(sa, 18);
+ lp = (int *)(sa->sa_len + (char *)sa);
+ if ((char *)lp < (char *)wp && *lp) {
+#ifdef DEBUG
+ logprintf(" flag = %x, rest = %d", rtm->rtm_flags, *lp);
+#endif
+ wp = (u_char *)(lp + 1);
+ mask = 0;
+ for (nb = *lp; nb > 4; nb--) {
+ mask <<= 8;
+ mask |= *wp++;
+ }
+ for (nb = 8 - *lp; nb > 0; nb--)
+ mask <<= 8;
+ }
+ }
+ printf("%08x ", mask);
+ p_flags(rtm->rtm_flags & (RTF_UP|RTF_GATEWAY|RTF_HOST), "%-6.6s ");
+ printf("(%d)\n", rtm->rtm_index);
+ }
+
+ return(1);
+}
+
+/*
+ * Delete routes associated with our interface
+ */
+void
+DeleteIfRoutes(all)
+int all;
+{
+ struct rt_msghdr *rtm;
+ struct sockaddr *sa;
+ struct in_addr dstnet, gateway;
+ int needed;
+ char *sp, *cp, *ep;
+ u_long mask;
+ int *lp, nb;
+ u_char *wp;
+#if ( __FreeBSD_version >= 199412 )
+ int mib[6];
+#endif
+
+#ifdef DEBUG
+ logprintf("DeleteIfRoutes (%d)\n", IfIndex);
+#endif
+#if ( __FreeBSD_version >= 199412 )
+ mib[0] = CTL_NET;
+ mib[1] = PF_ROUTE;
+ mib[2] = 0; /* protocol */
+ mib[3] = 0; /* wildcard address family */
+ mib[4] = NET_RT_DUMP;
+ mib[5] = 0; /* no flags */
+ needed = sysctl(mib, 6, NULL, &needed, NULL, 0 );
+#else
+ needed = getkerninfo(KINFO_RT_DUMP, 0, 0, 0);
+#endif
+ if (needed < 0)
+ return;
+
+ sp = malloc(needed);
+ if (sp == NULL)
+ return;
+
+#if ( __FreeBSD_version >= 199412 )
+ if (sysctl(mib, 6, sp, &needed, NULL, 0 ) < 0) {
+ free(sp);
+ return;
+ }
+#else
+ if (getkerninfo(KINFO_RT_DUMP, sp, &needed, 0) < 0) {
+ free(sp);
+ return;
+ }
+#endif
+ ep = sp + needed;
+
+ for (cp = sp; cp < ep; cp += rtm->rtm_msglen) {
+ rtm = (struct rt_msghdr *)cp;
+ sa = (struct sockaddr *)(rtm + 1);
+#ifdef DEBUG
+ logprintf("addrs: %x, index: %d, flags: %x, dstnet: %x\n",
+ rtm->rtm_addrs, rtm->rtm_index, rtm->rtm_flags,
+ ((struct sockaddr_in *)sa)->sin_addr);
+#endif
+ if (rtm->rtm_addrs != RTA_DST &&
+ (rtm->rtm_index == IfIndex) &&
+ (all || (rtm->rtm_flags & RTF_GATEWAY))) {
+ dstnet = ((struct sockaddr_in *)sa)->sin_addr;
+ wp = (u_char *)cp + rtm->rtm_msglen;
+ if (sa->sa_len == 0)
+ sa->sa_len = sizeof(long);
+ sa = (struct sockaddr *)(sa->sa_len + (char *)sa);
+ gateway = ((struct sockaddr_in *)sa)->sin_addr;
+ lp = (int *)(sa->sa_len + (char *)sa);
+ mask = 0;
+ if ((char *)lp < (char *)wp && *lp) {
+#ifdef DEBUG
+ printf(" flag = %x, rest = %d", rtm->rtm_flags, *lp);
+#endif
+ wp = (u_char *)(lp + 1);
+ for (nb = *lp; nb > 4; nb--) {
+ mask <<= 8;
+ mask |= *wp++;
+ }
+ for (nb = 8 - *lp; nb > 0; nb--)
+ mask <<= 8;
+ }
+#ifdef DEBUG
+ logprintf("## %s ", inet_ntoa(dstnet));
+ logprintf(" %s %d\n", inet_ntoa(gateway), rtm->rtm_index);
+#endif
+ if (dstnet.s_addr == INADDR_ANY) {
+ gateway.s_addr = INADDR_ANY;
+ mask = INADDR_ANY;
+ }
+ OsSetRoute(RTM_DELETE, dstnet, gateway, htonl(mask));
+ }
+#ifdef DEBUG
+ else if (rtm->rtm_index == IfIndex) {
+ logprintf("??? addrs: %x, flags = %x\n", rtm->rtm_addrs, rtm->rtm_flags);
+ }
+#endif
+ }
+ free(sp);
+}
+
+int
+GetIfIndex(name)
+char *name;
+{
+ struct ifreq *ifrp;
+ int s, len, elen, index;
+ struct ifconf ifconfs;
+ struct ifreq reqbuf[32];
+
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s < 0) {
+ perror("socket");
+ return(-1);
+ }
+
+ ifconfs.ifc_len = sizeof(reqbuf);
+ ifconfs.ifc_buf = (caddr_t)reqbuf;
+ if (ioctl(s, SIOCGIFCONF, &ifconfs) < 0) {
+ perror("IFCONF");
+ return(-1);
+ }
+
+ ifrp = ifconfs.ifc_req;
+
+ index = 1;
+ for (len = ifconfs.ifc_len; len > 0; len -= sizeof(struct ifreq)) {
+ elen = ifrp->ifr_addr.sa_len - sizeof(struct sockaddr);
+ if (ifrp->ifr_addr.sa_family == AF_LINK) {
+#ifdef DEBUG
+ logprintf("%d: %-*.*s, %d, %d\n", index, IFNAMSIZ, IFNAMSIZ, ifrp->ifr_name,
+ ifrp->ifr_addr.sa_family, elen);
+#endif
+ if (strcmp(ifrp->ifr_name, name) == 0) {
+ IfIndex = index;
+ return(index);
+ }
+#if defined(__FreeBSD__) || (_BSDI_VERSION >= 199312)
+ index++;
+#endif
+ }
+
+ len -= elen;
+ ifrp = (struct ifreq *)((char *)ifrp + elen);
+ ifrp++;
+#if defined(_BSDI_VERSION) && (_BSDI_VERSION < 199312)
+ index++;
+#endif
+ }
+
+ close(s);
+ return(-1);
+}
diff --git a/usr.sbin/ppp/slcompress.c b/usr.sbin/ppp/slcompress.c
new file mode 100644
index 0000000..b3c6403
--- /dev/null
+++ b/usr.sbin/ppp/slcompress.c
@@ -0,0 +1,589 @@
+/*
+ * Routines to compress and uncompess tcp packets (for transmission
+ * over low speed serial lines.
+ *
+ * Copyright (c) 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * 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 University of California, Berkeley. The name of the
+ * University 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:$
+ *
+ * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989:
+ * - Initial distribution.
+ */
+#ifndef lint
+static char rcsid[] = "$Header";
+#endif
+
+#include "defs.h"
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <netinet/ip.h>
+#include "slcompress.h"
+
+struct slstat slstat;
+
+#define INCR(counter) slstat.counter++;
+
+#define BCMP(p1, p2, n) bcmp((char *)(p1), (char *)(p2), (int)(n))
+#define BCOPY(p1, p2, n) bcopy((char *)(p1), (char *)(p2), (int)(n))
+#ifndef KERNEL
+#define ovbcopy bcopy
+#endif
+
+static int reason1, reason2, reason3, reason4, reason5;
+
+void
+sl_compress_init(comp)
+ struct slcompress *comp;
+{
+ register u_int i;
+ register struct cstate *tstate = comp->tstate;
+
+ bzero((char *)comp, sizeof(*comp));
+ for (i = MAX_STATES - 1; i > 0; --i) {
+ tstate[i].cs_id = i;
+ tstate[i].cs_next = &tstate[i - 1];
+ }
+ tstate[0].cs_next = &tstate[MAX_STATES - 1];
+ tstate[0].cs_id = 0;
+ comp->last_cs = &tstate[0];
+ comp->last_recv = 255;
+ comp->last_xmit = 255;
+ comp->flags = SLF_TOSS;
+}
+
+
+/* ENCODE encodes a number that is known to be non-zero. ENCODEZ
+ * checks for zero (since zero has to be encoded in the long, 3 byte
+ * form).
+ */
+#define ENCODE(n) { \
+ if ((u_short)(n) >= 256) { \
+ *cp++ = 0; \
+ cp[1] = (n); \
+ cp[0] = (n) >> 8; \
+ cp += 2; \
+ } else { \
+ *cp++ = (n); \
+ } \
+}
+#define ENCODEZ(n) { \
+ if ((u_short)(n) >= 256 || (u_short)(n) == 0) { \
+ *cp++ = 0; \
+ cp[1] = (n); \
+ cp[0] = (n) >> 8; \
+ cp += 2; \
+ } else { \
+ *cp++ = (n); \
+ } \
+}
+
+#define DECODEL(f) { \
+ if (*cp == 0) {\
+ (f) = htonl(ntohl(f) + ((cp[1] << 8) | cp[2])); \
+ cp += 3; \
+ } else { \
+ (f) = htonl(ntohl(f) + (u_long)*cp++); \
+ } \
+}
+
+#define DECODES(f) { \
+ if (*cp == 0) {\
+ (f) = htons(ntohs(f) + ((cp[1] << 8) | cp[2])); \
+ cp += 3; \
+ } else { \
+ (f) = htons(ntohs(f) + (u_long)*cp++); \
+ } \
+}
+
+#define DECODEU(f) { \
+ if (*cp == 0) {\
+ (f) = htons((cp[1] << 8) | cp[2]); \
+ cp += 3; \
+ } else { \
+ (f) = htons((u_long)*cp++); \
+ } \
+}
+
+
+u_char
+sl_compress_tcp(m, ip, comp, compress_cid)
+ struct mbuf *m;
+ register struct ip *ip;
+ struct slcompress *comp;
+ int compress_cid;
+{
+ register struct cstate *cs = comp->last_cs->cs_next;
+ register u_int hlen = ip->ip_hl;
+ register struct tcphdr *oth;
+ register struct tcphdr *th;
+ register u_int deltaS, deltaA;
+ register u_int changes = 0;
+ u_char new_seq[16];
+ register u_char *cp = new_seq;
+
+ /*
+ * Bail if this is an IP fragment or if the TCP packet isn't
+ * `compressible' (i.e., ACK isn't set or some other control bit is
+ * set). (We assume that the caller has already made sure the
+ * packet is IP proto TCP).
+ */
+#ifdef DEBUG
+ if ((ip->ip_off & htons(0x3fff)) || m->cnt < 40) {
+ logprintf("??? 1 ip_off = %x, cnt = %d\n", ip->ip_off, m->cnt);
+ DumpBp(m);
+ return (TYPE_IP);
+ }
+#else
+ if ((ip->ip_off & htons(0x3fff)) || m->cnt < 40)
+ return (TYPE_IP);
+#endif
+
+ th = (struct tcphdr *)&((int *)ip)[hlen];
+#ifdef DEBUG
+ if ((th->th_flags & (TH_SYN|TH_FIN|TH_RST|TH_ACK)) != TH_ACK) {
+ logprintf("??? 2 th_flags = %x\n", th->th_flags);
+ DumpBp(m);
+ return (TYPE_IP);
+ }
+#else
+ if ((th->th_flags & (TH_SYN|TH_FIN|TH_RST|TH_ACK)) != TH_ACK)
+ return (TYPE_IP);
+#endif
+
+ /*
+ * Packet is compressible -- we're going to send either a
+ * COMPRESSED_TCP or UNCOMPRESSED_TCP packet. Either way we need
+ * to locate (or create) the connection state. Special case the
+ * most recently used connection since it's most likely to be used
+ * again & we don't have to do any reordering if it's used.
+ */
+ INCR(sls_packets)
+ if (ip->ip_src.s_addr != cs->cs_ip.ip_src.s_addr ||
+ ip->ip_dst.s_addr != cs->cs_ip.ip_dst.s_addr ||
+ *(int *)th != ((int *)&cs->cs_ip)[cs->cs_ip.ip_hl]) {
+ /*
+ * Wasn't the first -- search for it.
+ *
+ * States are kept in a circularly linked list with
+ * last_cs pointing to the end of the list. The
+ * list is kept in lru order by moving a state to the
+ * head of the list whenever it is referenced. Since
+ * the list is short and, empirically, the connection
+ * we want is almost always near the front, we locate
+ * states via linear search. If we don't find a state
+ * for the datagram, the oldest state is (re-)used.
+ */
+ register struct cstate *lcs;
+ register struct cstate *lastcs = comp->last_cs;
+
+ do {
+ lcs = cs; cs = cs->cs_next;
+ INCR(sls_searches)
+ if (ip->ip_src.s_addr == cs->cs_ip.ip_src.s_addr
+ && ip->ip_dst.s_addr == cs->cs_ip.ip_dst.s_addr
+ && *(int *)th == ((int *)&cs->cs_ip)[cs->cs_ip.ip_hl])
+ goto found;
+ } while (cs != lastcs);
+
+ /*
+ * Didn't find it -- re-use oldest cstate. Send an
+ * uncompressed packet that tells the other side what
+ * connection number we're using for this conversation.
+ * Note that since the state list is circular, the oldest
+ * state points to the newest and we only need to set
+ * last_cs to update the lru linkage.
+ */
+ INCR(sls_misses)
+ comp->last_cs = lcs;
+#define THOFFSET(th) (th->th_off)
+ hlen += th->th_off;
+ hlen <<= 2;
+ if (hlen > m->cnt)
+ return(TYPE_IP);
+reason1++;
+ goto uncompressed;
+
+ found:
+ /*
+ * Found it -- move to the front on the connection list.
+ */
+ if (cs == lastcs)
+ comp->last_cs = lcs;
+ else {
+ lcs->cs_next = cs->cs_next;
+ cs->cs_next = lastcs->cs_next;
+ lastcs->cs_next = cs;
+ }
+ }
+
+ /*
+ * Make sure that only what we expect to change changed. The first
+ * line of the `if' checks the IP protocol version, header length &
+ * type of service. The 2nd line checks the "Don't fragment" bit.
+ * The 3rd line checks the time-to-live and protocol (the protocol
+ * check is unnecessary but costless). The 4th line checks the TCP
+ * header length. The 5th line checks IP options, if any. The 6th
+ * line checks TCP options, if any. If any of these things are
+ * different between the previous & current datagram, we send the
+ * current datagram `uncompressed'.
+ */
+ oth = (struct tcphdr *)&((int *)&cs->cs_ip)[hlen];
+ deltaS = hlen;
+ hlen += th->th_off;
+ hlen <<= 2;
+ if (hlen > m->cnt)
+ return(TYPE_IP);
+
+ if (((u_short *)ip)[0] != ((u_short *)&cs->cs_ip)[0] ||
+ ((u_short *)ip)[3] != ((u_short *)&cs->cs_ip)[3] ||
+ ((u_short *)ip)[4] != ((u_short *)&cs->cs_ip)[4] ||
+ THOFFSET(th) != THOFFSET(oth) ||
+ (deltaS > 5 &&
+ BCMP(ip + 1, &cs->cs_ip + 1, (deltaS - 5) << 2)) ||
+ (THOFFSET(th) > 5 &&
+ BCMP(th + 1, oth + 1, (THOFFSET(th) - 5) << 2))) {
+reason2++;
+ goto uncompressed;
+ }
+
+ /*
+ * Figure out which of the changing fields changed. The
+ * receiver expects changes in the order: urgent, window,
+ * ack, seq (the order minimizes the number of temporaries
+ * needed in this section of code).
+ */
+ if (th->th_flags & TH_URG) {
+ deltaS = ntohs(th->th_urp);
+ ENCODEZ(deltaS);
+ changes |= NEW_U;
+ } else if (th->th_urp != oth->th_urp) {
+ /* argh! URG not set but urp changed -- a sensible
+ * implementation should never do this but RFC793
+ * doesn't prohibit the change so we have to deal
+ * with it. */
+reason3++;
+ goto uncompressed;
+ }
+
+ deltaS = (u_short)(ntohs(th->th_win) - ntohs(oth->th_win));
+ if (deltaS) {
+ ENCODE(deltaS);
+ changes |= NEW_W;
+ }
+
+ deltaA = ntohl(th->th_ack) - ntohl(oth->th_ack);
+ if (deltaA) {
+ if (deltaA > 0xffff) {
+reason4++;
+ goto uncompressed;
+ }
+ ENCODE(deltaA);
+ changes |= NEW_A;
+ }
+
+ deltaS = ntohl(th->th_seq) - ntohl(oth->th_seq);
+ if (deltaS) {
+ if (deltaS > 0xffff) {
+ reason4++;
+ goto uncompressed;
+ }
+ ENCODE(deltaS);
+ changes |= NEW_S;
+ }
+
+ switch(changes) {
+
+ case 0:
+ /*
+ * Nothing changed. If this packet contains data and the
+ * last one didn't, this is probably a data packet following
+ * an ack (normal on an interactive connection) and we send
+ * it compressed. Otherwise it's probably a retransmit,
+ * retransmitted ack or window probe. Send it uncompressed
+ * in case the other side missed the compressed version.
+ */
+ if (ip->ip_len != cs->cs_ip.ip_len &&
+ ntohs(cs->cs_ip.ip_len) == hlen)
+ break;
+
+ /* (fall through) */
+
+ case SPECIAL_I:
+ case SPECIAL_D:
+ /*
+ * actual changes match one of our special case encodings --
+ * send packet uncompressed.
+ */
+reason5++;
+ goto uncompressed;
+
+ case NEW_S|NEW_A:
+ if (deltaS == deltaA &&
+ deltaS == ntohs(cs->cs_ip.ip_len) - hlen) {
+ /* special case for echoed terminal traffic */
+ changes = SPECIAL_I;
+ cp = new_seq;
+ }
+ break;
+
+ case NEW_S:
+ if (deltaS == ntohs(cs->cs_ip.ip_len) - hlen) {
+ /* special case for data xfer */
+ changes = SPECIAL_D;
+ cp = new_seq;
+ }
+ break;
+ }
+
+ deltaS = ntohs(ip->ip_id) - ntohs(cs->cs_ip.ip_id);
+ if (deltaS != 1) {
+ ENCODEZ(deltaS);
+ changes |= NEW_I;
+ }
+ if (th->th_flags & TH_PUSH)
+ changes |= TCP_PUSH_BIT;
+ /*
+ * Grab the cksum before we overwrite it below. Then update our
+ * state with this packet's header.
+ */
+ deltaA = ntohs(th->th_sum);
+ BCOPY(ip, &cs->cs_ip, hlen);
+
+ /*
+ * We want to use the original packet as our compressed packet.
+ * (cp - new_seq) is the number of bytes we need for compressed
+ * sequence numbers. In addition we need one byte for the change
+ * mask, one for the connection id and two for the tcp checksum.
+ * So, (cp - new_seq) + 4 bytes of header are needed. hlen is how
+ * many bytes of the original packet to toss so subtract the two to
+ * get the new packet size.
+ */
+ deltaS = cp - new_seq;
+ cp = (u_char *)ip;
+
+ /*
+ * Since fastq traffic can jump ahead of the background traffic,
+ * we don't know what order packets will go on the line. In this
+ * case, we always send a "new" connection id so the receiver state
+ * stays synchronized.
+ */
+#ifdef SL_NOFASTQ
+ if (comp->last_xmit == cs->cs_id) {
+ hlen -= deltaS + 3;
+ cp += hlen;
+ *cp++ = changes;
+ } else
+#endif
+ {
+ comp->last_xmit = cs->cs_id;
+ hlen -= deltaS + 4;
+ cp += hlen;
+ *cp++ = changes | NEW_C;
+ *cp++ = cs->cs_id;
+ }
+ m->cnt -= hlen;
+ m->offset += hlen;
+ *cp++ = deltaA >> 8;
+ *cp++ = deltaA;
+ BCOPY(new_seq, cp, deltaS);
+ INCR(sls_compressed)
+ return (TYPE_COMPRESSED_TCP);
+
+ /*
+ * Update connection state cs & send uncompressed packet ('uncompressed'
+ * means a regular ip/tcp packet but with the 'conversation id' we hope
+ * to use on future compressed packets in the protocol field).
+ */
+uncompressed:
+ BCOPY(ip, &cs->cs_ip, hlen);
+ ip->ip_p = cs->cs_id;
+ comp->last_xmit = cs->cs_id;
+ return (TYPE_UNCOMPRESSED_TCP);
+}
+
+
+int
+sl_uncompress_tcp(bufp, len, type, comp)
+ u_char **bufp;
+ int len;
+ u_int type;
+ struct slcompress *comp;
+{
+ register u_char *cp;
+ register u_int hlen, changes;
+ register struct tcphdr *th;
+ register struct cstate *cs;
+ register struct ip *ip;
+
+ switch (type) {
+
+ case TYPE_UNCOMPRESSED_TCP:
+ ip = (struct ip *) *bufp;
+ if (ip->ip_p >= MAX_STATES)
+ goto bad;
+ cs = &comp->rstate[comp->last_recv = ip->ip_p];
+ comp->flags &=~ SLF_TOSS;
+ ip->ip_p = IPPROTO_TCP;
+ hlen = ip->ip_hl;
+ th = (struct tcphdr *)&((int *)ip)[hlen];
+ hlen += THOFFSET(th);
+ hlen <<= 2;
+ BCOPY(ip, &cs->cs_ip, hlen);
+ cs->cs_ip.ip_sum = 0;
+ cs->cs_hlen = hlen;
+ INCR(sls_uncompressedin)
+ return (len);
+
+ default:
+ goto bad;
+
+ case TYPE_COMPRESSED_TCP:
+ break;
+ }
+ /* We've got a compressed packet. */
+ INCR(sls_compressedin)
+ cp = *bufp;
+ changes = *cp++;
+#ifdef DEBUG
+ logprintf("compressed: changes = %02x\n", changes);
+#endif
+ if (changes & NEW_C) {
+ /* Make sure the state index is in range, then grab the state.
+ * If we have a good state index, clear the 'discard' flag. */
+ if (*cp >= MAX_STATES)
+ goto bad;
+
+ comp->flags &=~ SLF_TOSS;
+ comp->last_recv = *cp++;
+ } else {
+ /* this packet has an implicit state index. If we've
+ * had a line error since the last time we got an
+ * explicit state index, we have to toss the packet. */
+ if (comp->flags & SLF_TOSS) {
+ INCR(sls_tossed)
+ return (0);
+ }
+ }
+ cs = &comp->rstate[comp->last_recv];
+ hlen = cs->cs_ip.ip_hl << 2;
+ th = (struct tcphdr *)&((u_char *)&cs->cs_ip)[hlen];
+ th->th_sum = htons((*cp << 8) | cp[1]);
+ cp += 2;
+ if (changes & TCP_PUSH_BIT)
+ th->th_flags |= TH_PUSH;
+ else
+ th->th_flags &=~ TH_PUSH;
+
+ switch (changes & SPECIALS_MASK) {
+ case SPECIAL_I:
+ {
+ register u_int i = ntohs(cs->cs_ip.ip_len) - cs->cs_hlen;
+ th->th_ack = htonl(ntohl(th->th_ack) + i);
+ th->th_seq = htonl(ntohl(th->th_seq) + i);
+ }
+ break;
+
+ case SPECIAL_D:
+ th->th_seq = htonl(ntohl(th->th_seq) + ntohs(cs->cs_ip.ip_len)
+ - cs->cs_hlen);
+ break;
+
+ default:
+ if (changes & NEW_U) {
+ th->th_flags |= TH_URG;
+ DECODEU(th->th_urp)
+ } else
+ th->th_flags &=~ TH_URG;
+ if (changes & NEW_W)
+ DECODES(th->th_win)
+ if (changes & NEW_A)
+ DECODEL(th->th_ack)
+ if (changes & NEW_S) {
+#ifdef DEBUG
+ logprintf("NEW_S: %02x, %02x, %02x\r\n", *cp, cp[1], cp[2]);
+#endif
+ DECODEL(th->th_seq)
+ }
+ break;
+ }
+ if (changes & NEW_I) {
+ DECODES(cs->cs_ip.ip_id)
+ } else
+ cs->cs_ip.ip_id = htons(ntohs(cs->cs_ip.ip_id) + 1);
+#ifdef DEBUG
+ logprintf("id = %04x, seq = %08x\r\n", cs->cs_ip.ip_id, ntohl(th->th_seq));
+#endif
+
+ /*
+ * At this point, cp points to the first byte of data in the
+ * packet. If we're not aligned on a 4-byte boundary, copy the
+ * data down so the ip & tcp headers will be aligned. Then back up
+ * cp by the tcp/ip header length to make room for the reconstructed
+ * header (we assume the packet we were handed has enough space to
+ * prepend 128 bytes of header). Adjust the length to account for
+ * the new header & fill in the IP total length.
+ */
+ len -= (cp - *bufp);
+ if (len < 0)
+ /* we must have dropped some characters (crc should detect
+ * this but the old slip framing won't) */
+ goto bad;
+
+#ifdef notdef
+ if ((int)cp & 3) {
+ if (len > 0)
+ (void) ovbcopy(cp, (caddr_t)((int)cp &~ 3), len);
+ cp = (u_char *)((int)cp &~ 3);
+ }
+#endif
+
+ cp -= cs->cs_hlen;
+ len += cs->cs_hlen;
+ cs->cs_ip.ip_len = htons(len);
+ BCOPY(&cs->cs_ip, cp, cs->cs_hlen);
+ *bufp = cp;
+
+ /* recompute the ip header checksum */
+ {
+ register u_short *bp = (u_short *)cp;
+ for (changes = 0; hlen > 0; hlen -= 2)
+ changes += *bp++;
+ changes = (changes & 0xffff) + (changes >> 16);
+ changes = (changes & 0xffff) + (changes >> 16);
+ ((struct ip *)cp)->ip_sum = ~ changes;
+ }
+ return (len);
+bad:
+ comp->flags |= SLF_TOSS;
+ INCR(sls_errorin)
+ return (0);
+}
+
+int
+ReportCompress()
+{
+ printf("Out: %d (compress) / %d (total)",
+ slstat.sls_compressed, slstat.sls_packets);
+ printf(" %d (miss) / %d (search)\n",
+ slstat.sls_misses, slstat.sls_searches);
+ printf("In: %d (compress), %d (uncompress)",
+ slstat.sls_compressedin, slstat.sls_uncompressedin);
+ printf(" %d (error), %d (tossed)\n",
+ slstat.sls_errorin, slstat.sls_tossed);
+ printf("%d, %d, %d, %d, %d\n", reason1, reason2, reason3, reason4, reason5);
+ return(1);
+}
diff --git a/usr.sbin/ppp/slcompress.h b/usr.sbin/ppp/slcompress.h
new file mode 100644
index 0000000..b21c80a
--- /dev/null
+++ b/usr.sbin/ppp/slcompress.h
@@ -0,0 +1,142 @@
+/*
+ * Definitions for tcp compression routines.
+ *
+ * $Header: /home/tony-o/src/ppp/RCS/slcompress.h,v 1.1 1993/09/11 05:30:49 tony-o Exp tony-o $
+ *
+ * Copyright (c) 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * 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 University of California, Berkeley. The name of the
+ * University 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:$
+ * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989:
+ * - Initial distribution.
+ */
+
+#define MAX_STATES 16 /* must be > 2 and < 256 */
+#define MAX_HDR 128 /* XXX 4bsd-ism: should really be 128 */
+
+/*
+ * Compressed packet format:
+ *
+ * The first octet contains the packet type (top 3 bits), TCP
+ * 'push' bit, and flags that indicate which of the 4 TCP sequence
+ * numbers have changed (bottom 5 bits). The next octet is a
+ * conversation number that associates a saved IP/TCP header with
+ * the compressed packet. The next two octets are the TCP checksum
+ * from the original datagram. The next 0 to 15 octets are
+ * sequence number changes, one change per bit set in the header
+ * (there may be no changes and there are two special cases where
+ * the receiver implicitly knows what changed -- see below).
+ *
+ * There are 5 numbers which can change (they are always inserted
+ * in the following order): TCP urgent pointer, window,
+ * acknowlegement, sequence number and IP ID. (The urgent pointer
+ * is different from the others in that its value is sent, not the
+ * change in value.) Since typical use of SLIP links is biased
+ * toward small packets (see comments on MTU/MSS below), changes
+ * use a variable length coding with one octet for numbers in the
+ * range 1 - 255 and 3 octets (0, MSB, LSB) for numbers in the
+ * range 256 - 65535 or 0. (If the change in sequence number or
+ * ack is more than 65535, an uncompressed packet is sent.)
+ */
+
+/*
+ * Packet types (must not conflict with IP protocol version)
+ *
+ * The top nibble of the first octet is the packet type. There are
+ * three possible types: IP (not proto TCP or tcp with one of the
+ * control flags set); uncompressed TCP (a normal IP/TCP packet but
+ * with the 8-bit protocol field replaced by an 8-bit connection id --
+ * this type of packet syncs the sender & receiver); and compressed
+ * TCP (described above).
+ *
+ * LSB of 4-bit field is TCP "PUSH" bit (a worthless anachronism) and
+ * is logically part of the 4-bit "changes" field that follows. Top
+ * three bits are actual packet type. For backward compatibility
+ * and in the interest of conserving bits, numbers are chosen so the
+ * IP protocol version number (4) which normally appears in this nibble
+ * means "IP packet".
+ */
+
+/* packet types */
+#define TYPE_IP 0x40
+#define TYPE_UNCOMPRESSED_TCP 0x70
+#define TYPE_COMPRESSED_TCP 0x80
+#define TYPE_ERROR 0x00
+
+/* Bits in first octet of compressed packet */
+#define NEW_C 0x40 /* flag bits for what changed in a packet */
+#define NEW_I 0x20
+#define NEW_S 0x08
+#define NEW_A 0x04
+#define NEW_W 0x02
+#define NEW_U 0x01
+
+/* reserved, special-case values of above */
+#define SPECIAL_I (NEW_S|NEW_W|NEW_U) /* echoed interactive traffic */
+#define SPECIAL_D (NEW_S|NEW_A|NEW_W|NEW_U) /* unidirectional data */
+#define SPECIALS_MASK (NEW_S|NEW_A|NEW_W|NEW_U)
+
+#define TCP_PUSH_BIT 0x10
+
+/*
+ * "state" data for each active tcp conversation on the wire. This is
+ * basically a copy of the entire IP/TCP header from the last packet
+ * we saw from the conversation together with a small identifier
+ * the transmit & receive ends of the line use to locate saved header.
+ */
+struct cstate {
+ struct cstate *cs_next; /* next most recently used cstate (xmit only) */
+ u_short cs_hlen; /* size of hdr (receive only) */
+ u_char cs_id; /* connection # associated with this state */
+ u_char cs_filler;
+ union {
+ char csu_hdr[MAX_HDR];
+ struct ip csu_ip; /* ip/tcp hdr from most recent packet */
+ } slcs_u;
+};
+#define cs_ip slcs_u.csu_ip
+#define cs_hdr slcs_u.csu_hdr
+
+/*
+ * all the state data for one serial line (we need one of these
+ * per line).
+ */
+struct slcompress {
+ struct cstate *last_cs; /* most recently used tstate */
+ u_char last_recv; /* last rcvd conn. id */
+ u_char last_xmit; /* last sent conn. id */
+ u_short flags;
+ struct cstate tstate[MAX_STATES]; /* xmit connection states */
+ struct cstate rstate[MAX_STATES]; /* receive connection states */
+};
+
+struct slstat {
+ int sls_packets; /* outbound packets */
+ int sls_compressed; /* outbound compressed packets */
+ int sls_searches; /* searches for connection state */
+ int sls_misses; /* times couldn't find conn. state */
+ int sls_uncompressedin; /* inbound uncompressed packets */
+ int sls_compressedin; /* inbound compressed packets */
+ int sls_errorin; /* inbound unknown type packets */
+ int sls_tossed; /* inbound packets tossed because of error */
+};
+
+/* flag values */
+#define SLF_TOSS 1 /* tossing rcvd frames because of input err */
+
+extern void sl_compress_init(/* struct slcompress * */);
+extern u_char sl_compress_tcp(/* struct mbuf *, struct ip *,
+ struct slcompress *, int compress_cid_flag */);
+extern int sl_uncompress_tcp(/* u_char **, int, u_char, struct slcompress * */);
diff --git a/usr.sbin/ppp/systems.c b/usr.sbin/ppp/systems.c
new file mode 100644
index 0000000..3f0ad82
--- /dev/null
+++ b/usr.sbin/ppp/systems.c
@@ -0,0 +1,215 @@
+/*
+ * System configuration routines
+ *
+ * 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:
+ */
+#include "fsm.h"
+#include "vars.h"
+#include "ipcp.h"
+
+extern void DecodeCommand();
+
+static int uid, gid;
+static int euid, egid;
+static int usermode;
+
+void
+GetUid()
+{
+ uid = getuid();
+ gid = getgid();
+ euid = geteuid();
+ egid = getegid();
+ usermode = 0;
+}
+
+static void
+SetUserId()
+{
+ if (!usermode) {
+#ifdef __FreeBSD__
+ setruid(euid);
+ seteuid(uid);
+ setrgid(egid);
+ setegid(gid);
+#else
+ setreuid(euid, uid);
+ setregid(egid, gid);
+#endif
+ usermode = 1;
+ }
+}
+
+static void
+SetPppId()
+{
+ if (usermode) {
+#ifdef __FreeBSD__
+ setruid(uid);
+ seteuid(euid);
+ setrgid(gid);
+ setegid(egid);
+#else
+ setreuid(uid, euid);
+ setregid(gid, egid);
+#endif
+ usermode = 0;
+ }
+}
+
+FILE *
+OpenSecret(file)
+char *file;
+{
+ FILE *fp;
+ char *cp;
+ char line[100];
+
+ fp = NULL;
+ cp = getenv("HOME");
+ if (cp) {
+ SetUserId();
+ sprintf(line, "%s/.%s", cp, file);
+ fp = fopen(line, "r");
+ }
+ if (fp == NULL) {
+ SetPppId();
+ sprintf(line, "/etc/iijppp/%s", file);
+ fp = fopen(line, "r");
+ }
+ if (fp == NULL) {
+ fprintf(stderr, "can't open %s.\n", line);
+ SetPppId();
+ return(NULL);
+ }
+ return(fp);
+}
+
+void
+CloseSecret(fp)
+FILE *fp;
+{
+ fclose(fp);
+ SetPppId();
+}
+
+int
+SelectSystem(name, file)
+char *name;
+char *file;
+{
+ FILE *fp;
+ char *cp, *wp;
+ int n;
+ int val = -1;
+ char line[200];
+
+ fp = NULL;
+ cp = getenv("HOME");
+ if (cp) {
+ SetUserId();
+ sprintf(line, "%s/.%s", cp, file);
+ fp = fopen(line, "r");
+ }
+ if (fp == NULL) {
+ SetPppId(); /* fix from pdp@ark.jr3uom.iijnet.or.jp */
+ sprintf(line, "/etc/iijppp/%s", file);
+ fp = fopen(line, "r");
+ }
+ if (fp == NULL) {
+ fprintf(stderr, "can't open %s.\n", line);
+ SetPppId();
+ return(-1);
+ }
+#ifdef DEBUG
+ fprintf(stderr, "checking %s (%s).\n", name, line);
+#endif
+ while (fgets(line, sizeof(line), fp)) {
+ cp = line;
+ switch (*cp) {
+ case '#': /* comment */
+ break;
+ case ' ':
+ case '\t':
+ break;
+ default:
+ wp = strpbrk(cp, ":\n");
+ *wp = '\0';
+ if (strcmp(cp, name) == 0) {
+ while (fgets(line, sizeof(line), fp)) {
+ cp = line;
+ if (*cp == ' ' || *cp == '\t') {
+ n = strspn(cp, " \t");
+ cp += n;
+#ifdef DEBUG
+ fprintf(stderr, "%s", cp);
+#endif
+ SetPppId();
+ DecodeCommand(cp, strlen(cp), 0);
+ SetUserId();
+ } else if (*cp == '#') {
+ continue;
+ } else
+ break;
+ }
+ fclose(fp);
+ SetPppId();
+ return(0);
+ }
+ break;
+ }
+ }
+ fclose(fp);
+ SetPppId();
+ return(val);
+}
+
+int
+LoadCommand(list, argc, argv)
+struct cmdtab *list;
+int argc;
+char **argv;
+{
+ char *name;
+
+ if (argc > 0)
+ name = *argv;
+ else
+ name = "default";
+
+ if (SelectSystem(name, CONFFILE) < 0) {
+ printf("%s: not found.\n", name);
+ return(-1);
+ }
+ return(1);
+}
+
+extern struct in_addr ifnetmask;
+
+int
+SaveCommand(list, argc, argv)
+struct cmdtab *list;
+int argc;
+char **argv;
+{
+ printf("save command is not implemented (yet).\n");
+ return(1);
+}
diff --git a/usr.sbin/ppp/timeout.h b/usr.sbin/ppp/timeout.h
new file mode 100644
index 0000000..04b1ba1
--- /dev/null
+++ b/usr.sbin/ppp/timeout.h
@@ -0,0 +1,49 @@
+/*
+ * 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. 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:
+ */
+
+#ifndef _TIMEOUT_H_
+#define _TIMEOUT_H_
+
+#define TICKUNIT 10000 /* Unit in usec */
+#define SECTICKS (1000000/TICKUNIT)
+
+struct pppTimer {
+ int state;
+ u_long rest; /* Ticks to expire */
+ u_long load; /* Initial load value */
+ void (*func)(); /* Function called when timer is expired */
+ void *arg; /* Argument passed to timeout function */
+ struct pppTimer *next; /* Link to next timer */
+ struct pppTimer *enext; /* Link to next expired timer */
+};
+
+#define TIMER_STOPPED 0
+#define TIMER_RUNNING 1
+#define TIMER_EXPIRED 2
+
+struct pppTimer *TimerList;
+
+extern void StartTimer(struct pppTimer *);
+extern void StopTimer(struct pppTimer *);
+extern void TimerService(void);
+extern void StartIdleTimer(void);
+#endif /* _TIMEOUT_H_ */
diff --git a/usr.sbin/ppp/timer.c b/usr.sbin/ppp/timer.c
new file mode 100644
index 0000000..2c665da
--- /dev/null
+++ b/usr.sbin/ppp/timer.c
@@ -0,0 +1,151 @@
+/*
+ * PPP Timer Processing 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:
+ */
+#include "defs.h"
+#include <sys/time.h>
+#include <signal.h>
+#include "timeout.h"
+
+void
+StartTimer(tp)
+struct pppTimer *tp;
+{
+ struct pppTimer *t, *pt;
+ u_long ticks = 0;
+
+ if (tp->state == TIMER_RUNNING) {
+ StopTimer(tp);
+ }
+ if (tp->load == 0) {
+#ifdef DEBUG
+ logprintf("timer %x has 0 load!\n", tp);
+#endif
+ return;
+ }
+ pt = NULL;
+ for (t = TimerList; t; t = t->next) {
+#ifdef DEBUG
+ logprintf("%x(%d): ticks: %d, rest: %d\n", t, t->state, ticks, t->rest);
+#endif
+ if (ticks + t->rest >= tp->load)
+ break;
+ ticks += t->rest;
+ pt = t;
+ }
+
+ tp->state = TIMER_RUNNING;
+ tp->rest = tp->load - ticks;
+#ifdef DEBUG
+ logprintf("Inserting %x before %x, rest = %d\n", tp, t, tp->rest);
+#endif
+ /* Insert given *tp just before *t */
+ tp->next = t;
+ if (pt) {
+ pt->next = tp;
+ } else
+ TimerList = tp;
+ if (t)
+ t->rest -= tp->rest;
+}
+
+void
+StopTimer(tp)
+struct pppTimer *tp;
+{
+ struct pppTimer *t, *pt;
+
+ if (tp->state != TIMER_RUNNING) {
+ tp->next = NULL;
+ return;
+ }
+
+#ifdef DEBUG
+ logprintf("StopTimer: %x, next = %x\n", tp, tp->next);
+#endif
+ pt = NULL;
+ for (t = TimerList; t != tp; t = t->next)
+ pt = t;
+ if (t) {
+ if (pt)
+ pt->next = t->next;
+ else
+ TimerList = t->next;
+ if (t->next)
+ t->next->rest += tp->rest;
+ } else
+ fprintf(stderr, "Oops, timer not found!!\n");
+ tp->next = NULL;
+ tp->state = TIMER_STOPPED;
+}
+
+void
+TimerService()
+{
+ struct pppTimer *tp, *exp, *wt;
+
+ if (tp = TimerList) {
+ tp->rest--;
+ if (tp->rest == 0) {
+ /*
+ * Multiple timers may expires at once. Create list of expired timers.
+ */
+ exp = NULL;
+ do {
+ tp->state = TIMER_EXPIRED;
+ wt = tp->next;
+ tp->enext = exp;
+ exp = tp;
+#ifdef DEBUG
+ logprintf("Add %x to exp\n", tp);
+#endif
+ tp = wt;
+ } while (tp && (tp->rest == 0));
+
+ TimerList = tp;
+#ifdef DEBUG
+ logprintf("TimerService: next is %x(%d)\n",
+ TimerList, TimerList? TimerList->rest : 0);
+#endif
+ /*
+ * Process all expired timers.
+ */
+ while (exp) {
+#ifdef notdef
+ StopTimer(exp);
+#endif
+ if (exp->func)
+ (*exp->func)(exp->arg);
+ exp = exp->enext;
+ }
+ }
+ }
+}
+
+void
+ShowTimers()
+{
+ struct pppTimer *pt;
+
+ for (pt = TimerList; pt; pt = pt->next)
+ fprintf(stderr, "%x: load = %d, rest = %d\r\n", pt, pt->load, pt->rest);
+}
diff --git a/usr.sbin/ppp/uucplock.c b/usr.sbin/ppp/uucplock.c
new file mode 100644
index 0000000..b2f3e17
--- /dev/null
+++ b/usr.sbin/ppp/uucplock.c
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 1988 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id:$
+ *
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)uucplock.c 5.5 (Berkeley) 6/1/90";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/file.h>
+#include <sys/dir.h>
+#include <errno.h>
+#include "pathnames.h"
+
+/*
+ * uucp style locking routines
+ * return: 0 - success
+ * -1 - failure
+ */
+
+uu_lock(ttyname)
+ char *ttyname;
+{
+ extern int errno;
+ int fd, pid;
+ char tbuf[sizeof(_PATH_LOCKDIRNAME) + MAXNAMLEN];
+ off_t lseek();
+
+ (void)sprintf(tbuf, _PATH_LOCKDIRNAME, ttyname);
+ fd = open(tbuf, O_RDWR|O_CREAT|O_EXCL, 0664);
+ if (fd < 0) {
+ /*
+ * file is already locked
+ * check to see if the process holding the lock still exists
+ */
+ fd = open(tbuf, O_RDWR, 0);
+ if (fd < 0) {
+ perror("lock open");
+ return(-1);
+ }
+ if (read(fd, &pid, sizeof(pid)) != sizeof(pid)) {
+ (void)close(fd);
+ perror("lock read");
+ return(-1);
+ }
+
+ if (kill(pid, 0) == 0 || errno != ESRCH) {
+ (void)close(fd); /* process is still running */
+ return(-1);
+ }
+ /*
+ * The process that locked the file isn't running, so
+ * we'll lock it ourselves
+ */
+ if (lseek(fd, 0L, L_SET) < 0) {
+ (void)close(fd);
+ perror("lock lseek");
+ return(-1);
+ }
+ /* fall out and finish the locking process */
+ }
+ pid = getpid();
+ if (write(fd, (char *)&pid, sizeof(pid)) != sizeof(pid)) {
+ (void)close(fd);
+ (void)unlink(tbuf);
+ perror("lock write");
+ return(-1);
+ }
+ (void)close(fd);
+ return(0);
+}
+
+uu_unlock(ttyname)
+ char *ttyname;
+{
+ char tbuf[sizeof(_PATH_LOCKDIRNAME) + MAXNAMLEN];
+
+ (void)sprintf(tbuf, _PATH_LOCKDIRNAME, ttyname);
+ return(unlink(tbuf));
+}
diff --git a/usr.sbin/ppp/vars.c b/usr.sbin/ppp/vars.c
new file mode 100644
index 0000000..1298333
--- /dev/null
+++ b/usr.sbin/ppp/vars.c
@@ -0,0 +1,153 @@
+/*
+ * PPP configuration variables
+ *
+ * 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:$
+ */
+#include "fsm.h"
+#include "command.h"
+#include "hdlc.h"
+#include "termios.h"
+#include "vars.h"
+
+char VarVersion[] = "Version 0.93";
+
+/*
+ * Order of conf option is important. See vars.h.
+ */
+struct confdesc pppConfs[] = {
+ { "vjcomp", CONF_ENABLE, CONF_ACCEPT },
+ { "lqr", CONF_ENABLE, CONF_ACCEPT },
+ { "chap", CONF_DISABLE, CONF_ACCEPT },
+ { "pap", CONF_DISABLE, CONF_ACCEPT },
+ { "acfcomp", CONF_ENABLE, CONF_ACCEPT },
+ { "protocomp", CONF_ENABLE, CONF_ACCEPT },
+ { "pred1", CONF_ENABLE, CONF_ACCEPT },
+#ifdef notdef
+ { "ipaddress", CONF_ENABLE, CONF_ACCEPT },
+#endif
+ { NULL },
+};
+
+struct pppvars pppVars = {
+ DEF_MRU, 0, MODEM_SPEED, CS8, 180, 30,
+ MODEM_DEV, OPEN_PASSIVE,
+};
+
+int
+DisplayCommand()
+{
+ struct confdesc *vp;
+
+ printf("Current configuration option settings..\n\n");
+ printf("Name\t\tMy Side\t\tHis Side\n");
+ printf("----------------------------------------\n");
+ for (vp = pppConfs; vp->name; vp++)
+ printf("%-10s\t%s\t\t%s\n", vp->name,
+ (vp->myside == CONF_ENABLE)? "enable" : "disable",
+ (vp->hisside == CONF_ACCEPT)? "accept" : "deny");
+ return(1);
+}
+
+int
+DisableCommand(list, argc, argv)
+struct cmdtab *list;
+int argc;
+char **argv;
+{
+ struct confdesc *vp;
+
+ if (argc < 1) {
+ printf("disable what?\n");
+ return(1);
+ }
+ do {
+ for (vp = pppConfs; vp->name; vp++) {
+ if (strcasecmp(vp->name, *argv) == 0)
+ vp->myside = CONF_DISABLE;
+ }
+ argc--; argv++;
+ } while (argc > 0);
+ return(1);
+}
+
+int
+EnableCommand(list, argc, argv)
+struct cmdtab *list;
+int argc;
+char **argv;
+{
+ struct confdesc *vp;
+
+ if (argc < 1) {
+ printf("enable what?\n");
+ return(1);
+ }
+ do {
+ for (vp = pppConfs; vp->name; vp++) {
+ if (strcasecmp(vp->name, *argv) == 0)
+ vp->myside = CONF_ENABLE;
+ }
+ argc--; argv++;
+ } while (argc > 0);
+ return(1);
+}
+
+int
+AcceptCommand(list, argc, argv)
+struct cmdtab *list;
+int argc;
+char **argv;
+{
+ struct confdesc *vp;
+
+ if (argc < 1) {
+ printf("accept what?\n");
+ return(1);
+ }
+ do {
+ for (vp = pppConfs; vp->name; vp++) {
+ if (strcasecmp(vp->name, *argv) == 0)
+ vp->hisside = CONF_ACCEPT;
+ }
+ argc--; argv++;
+ } while (argc > 0);
+ return(1);
+}
+
+int
+DenyCommand(list, argc, argv)
+struct cmdtab *list;
+int argc;
+char **argv;
+{
+ struct confdesc *vp;
+
+ if (argc < 1) {
+ printf("enable what?\n");
+ return(1);
+ }
+ do {
+ for (vp = pppConfs; vp->name; vp++) {
+ if (strcasecmp(vp->name, *argv) == 0)
+ vp->hisside = CONF_DENY;
+ }
+ argc--; argv++;
+ } while (argc > 0);
+ return(1);
+}
diff --git a/usr.sbin/ppp/vars.h b/usr.sbin/ppp/vars.h
new file mode 100644
index 0000000..75dabdc
--- /dev/null
+++ b/usr.sbin/ppp/vars.h
@@ -0,0 +1,86 @@
+/*
+ * 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. 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:
+ */
+
+#ifndef _VARS_H_
+#define _VARS_H_
+
+struct confdesc {
+ char *name;
+ int myside, hisside;
+};
+
+#define CONF_DISABLE 0
+#define CONF_ENABLE 1
+
+#define CONF_DENY 0
+#define CONF_ACCEPT 1
+
+#define ConfVjcomp 0
+#define ConfLqr 1
+#define ConfChap 2
+#define ConfPap 3
+#define ConfAcfcomp 4
+#define ConfProtocomp 5
+#define ConfPred1 6
+#define ConfIpAddress 6
+#define MAXCONFS 7
+
+#define Enabled(x) (pppConfs[x].myside & CONF_ENABLE)
+#define Acceptable(x) (pppConfs[x].hisside & CONF_ACCEPT)
+
+extern struct confdesc pppConfs[MAXCONFS+1];
+
+struct pppvars {
+ u_long var_mru; /* Initial MRU value */
+ int var_accmap; /* Initial ACCMAP value */
+ int modem_speed; /* Current modem speed */
+ int modem_parity; /* Parity setting */
+ int idle_timeout; /* Idle timeout value */
+ int lqr_timeout; /* LQR timeout value */
+ char modem_dev[20]; /* Name of device */
+ int open_mode; /* LCP open mode */
+ char dial_script[200]; /* Dial script */
+ char login_script[200]; /* Login script */
+ char auth_key[50]; /* PAP/CHAP key */
+ char auth_name[50]; /* PAP/CHAP system name */
+ char phone_number[50]; /* Telephone Number */
+};
+
+#define VarAccmap pppVars.var_accmap
+#define VarMRU pppVars.var_mru
+#define VarDevice pppVars.modem_dev
+#define VarSpeed pppVars.modem_speed
+#define VarParity pppVars.modem_parity
+#define VarOpenMode pppVars.open_mode
+#define VarDialScript pppVars.dial_script
+#define VarLoginScript pppVars.login_script
+#define VarIdleTimeout pppVars.idle_timeout
+#define VarLqrTimeout pppVars.lqr_timeout
+#define VarAuthKey pppVars.auth_key
+#define VarAuthName pppVars.auth_name
+#define VarPhone pppVars.phone_number
+
+extern struct pppvars pppVars;
+
+int ipInOctets, ipOutOctets;
+int ipConnectSecs, ipIdleSecs;
+#endif
diff --git a/usr.sbin/ppp/vjcomp.c b/usr.sbin/ppp/vjcomp.c
new file mode 100644
index 0000000..06f13ed
--- /dev/null
+++ b/usr.sbin/ppp/vjcomp.c
@@ -0,0 +1,145 @@
+/*
+ * Input/Output VJ Compressed packets
+ *
+ * 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:
+ */
+#include "fsm.h"
+#include "lcpproto.h"
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include "slcompress.h"
+#include "hdlc.h"
+#include "ipcp.h"
+
+#define MAX_VJHEADER 16 /* Maximum size of compressed header */
+
+struct slcompress cslc;
+
+void
+VjInit()
+{
+ sl_compress_init(&cslc);
+}
+
+void
+SendPppFlame(pri, bp)
+int pri;
+struct mbuf *bp;
+{
+ int type;
+ int proto;
+ int cproto = IpcpInfo.his_compproto >> 16;
+
+#ifdef DEBUG
+ logprintf("SendPppFlame: proto = %x\n", IpcpInfo.his_compproto);
+#endif
+ if (cproto== PROTO_VJCOMP) {
+ type = sl_compress_tcp(bp, MBUF_CTOP(bp), &cslc, IpcpInfo.his_compproto & 0xff);
+
+#ifdef DEBUG
+ logprintf("type = %x\n", type);
+#endif
+ switch (type) {
+ case TYPE_IP:
+ proto = PROTO_IP;
+ break;
+ case TYPE_UNCOMPRESSED_TCP:
+ proto = PROTO_VJUNCOMP;
+ break;
+ case TYPE_COMPRESSED_TCP:
+ proto = PROTO_VJCOMP;
+ break;
+ default:
+ logprintf("unknown type %x\n", type);
+ pfree(bp);
+ return;
+ }
+ } else
+ proto = PROTO_IP;
+ HdlcOutput(pri, proto, bp);
+}
+
+static struct mbuf *
+VjUncompressTcp(bp, type)
+struct mbuf *bp;
+u_char type;
+{
+ u_char *bufp;
+ int len, olen, rlen;
+ struct mbuf *nbp;
+ u_char work[MAX_HDR+MAX_VJHEADER]; /* enough to hold TCP/IP header */
+
+ olen = len = plength(bp);
+ if (type == TYPE_UNCOMPRESSED_TCP) {
+ /*
+ * Uncompressed packet does NOT change its size, so that we can
+ * use mbuf space for uncompression job.
+ */
+ bufp = MBUF_CTOP(bp);
+ len = sl_uncompress_tcp(&bufp, len, type, &cslc);
+ return(bp);
+ }
+ /*
+ * Handle compressed packet.
+ * 1) Read upto MAX_VJHEADER bytes into work space.
+ * 2) Try to uncompress it.
+ * 3) Compute amount of necesary space.
+ * 4) Copy unread data info there.
+ */
+ if (len > MAX_VJHEADER) len = MAX_VJHEADER;
+ rlen = len;
+ bufp = work + MAX_HDR;
+ bp = mbread(bp, bufp, rlen);
+ len = sl_uncompress_tcp(&bufp, olen, type, &cslc);
+ len -= olen;
+ len += rlen;
+ nbp = mballoc(len, MB_VJCOMP);
+ bcopy(bufp, MBUF_CTOP(nbp), len);
+ nbp->next = bp;
+ return(nbp);
+}
+
+struct mbuf *
+VjCompInput(bp, proto)
+struct mbuf *bp;
+int proto;
+{
+ u_char type;
+
+#ifdef DEBUG
+ logprintf("VjCompInput (%02x):\n", proto);
+ DumpBp(bp);
+#endif
+
+ switch (proto) {
+ case PROTO_VJCOMP:
+ type = TYPE_COMPRESSED_TCP;
+ break;
+ case PROTO_VJUNCOMP:
+ type = TYPE_UNCOMPRESSED_TCP;
+ break;
+ default:
+ logprintf("???\n");
+ return(bp);
+ }
+ bp = VjUncompressTcp(bp, type);
+ return(bp);
+}
OpenPOWER on IntegriCloud