This commit is contained in:
Atsushi Murai 1995-01-31 06:29:58 +00:00
parent 4ffc792490
commit af57ed9fdc
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/cvs2svn/branches/R093/; revision=6059
54 changed files with 12369 additions and 0 deletions

12
usr.sbin/ppp/Makefile Normal file
View File

@ -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>

185
usr.sbin/ppp/async.c Normal file
View File

@ -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--;
}
}

112
usr.sbin/ppp/auth.c Normal file
View File

@ -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 */
}

281
usr.sbin/ppp/ccp.c Normal file
View File

@ -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);
}
}

52
usr.sbin/ppp/ccp.h Normal file
View File

@ -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

259
usr.sbin/ppp/chap.c Normal file
View File

@ -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);
}

32
usr.sbin/ppp/chap.h Normal file
View File

@ -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

377
usr.sbin/ppp/chat.c Normal file
View File

@ -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);
}

807
usr.sbin/ppp/command.c Normal file
View File

@ -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);
}

30
usr.sbin/ppp/command.h Normal file
View File

@ -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;
};

77
usr.sbin/ppp/defs.h Normal file
View File

@ -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_ */

475
usr.sbin/ppp/filter.c Normal file
View File

@ -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);
}

77
usr.sbin/ppp/filter.h Normal file
View File

@ -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_

802
usr.sbin/ppp/fsm.c Normal file
View File

@ -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
}

134
usr.sbin/ppp/fsm.h Normal file
View File

@ -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_ */

51
usr.sbin/ppp/global.h Normal file
View File

@ -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

378
usr.sbin/ppp/hdlc.c Normal file
View File

@ -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);
}

58
usr.sbin/ppp/hdlc.h Normal file
View File

@ -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

398
usr.sbin/ppp/ip.c Normal file
View File

@ -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--;
}
}

459
usr.sbin/ppp/ipcp.c Normal file
View File

@ -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);
}

62
usr.sbin/ppp/ipcp.h Normal file
View File

@ -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

656
usr.sbin/ppp/lcp.c Normal file
View File

@ -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);
}

83
usr.sbin/ppp/lcp.h Normal file
View File

@ -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

52
usr.sbin/ppp/lcpproto.h Normal file
View File

@ -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

223
usr.sbin/ppp/log.c Normal file
View File

@ -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);
}

53
usr.sbin/ppp/log.h Normal file
View File

@ -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

259
usr.sbin/ppp/lqr.c Normal file
View File

@ -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);
}
}

66
usr.sbin/ppp/lqr.h Normal file
View File

@ -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

693
usr.sbin/ppp/main.c Normal file
View File

@ -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");
}

187
usr.sbin/ppp/mbuf.c Normal file
View File

@ -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
}

67
usr.sbin/ppp/mbuf.h Normal file
View File

@ -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

38
usr.sbin/ppp/md5.h Normal file
View File

@ -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 *));

338
usr.sbin/ppp/md5c.c Normal file
View File

@ -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;
}

591
usr.sbin/ppp/modem.c Normal file
View File

@ -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);
}

37
usr.sbin/ppp/modem.h Normal file
View File

@ -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

341
usr.sbin/ppp/os.c Normal file
View File

@ -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;
{
}

34
usr.sbin/ppp/os.h Normal file
View File

@ -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

163
usr.sbin/ppp/pap.c Normal file
View File

@ -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);
}

29
usr.sbin/ppp/pap.h Normal file
View File

@ -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

50
usr.sbin/ppp/pathnames.h Normal file
View File

@ -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"

36
usr.sbin/ppp/phase.h Normal file
View File

@ -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

492
usr.sbin/ppp/ppp.8 Normal file
View File

@ -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)

492
usr.sbin/ppp/ppp.8.m4 Normal file
View File

@ -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)

237
usr.sbin/ppp/pred.c Normal file
View File

@ -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);
}

392
usr.sbin/ppp/route.c Normal file
View File

@ -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);
}

589
usr.sbin/ppp/slcompress.c Normal file
View File

@ -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);
}

142
usr.sbin/ppp/slcompress.h Normal file
View File

@ -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 * */);

215
usr.sbin/ppp/systems.c Normal file
View File

@ -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);
}

49
usr.sbin/ppp/timeout.h Normal file
View File

@ -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_ */

151
usr.sbin/ppp/timer.c Normal file
View File

@ -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);
}

112
usr.sbin/ppp/uucplock.c Normal file
View File

@ -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));
}

153
usr.sbin/ppp/vars.c Normal file
View File

@ -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);
}

86
usr.sbin/ppp/vars.h Normal file
View File

@ -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

145
usr.sbin/ppp/vjcomp.c Normal file
View File

@ -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);
}