6140ba1177
This structure contains the asynchronous state of the physical link. Unfortunately, just about every .h file is included in every .c file now. Fixing this can be one of the last jobs.
876 lines
21 KiB
C
876 lines
21 KiB
C
/*
|
|
* 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: lcp.c,v 1.55.2.6 1998/02/02 19:32:09 brian Exp $
|
|
*
|
|
* TODO:
|
|
* o Limit data field length by MRU
|
|
*/
|
|
#include <sys/param.h>
|
|
#include <sys/time.h>
|
|
#include <sys/socket.h>
|
|
#include <net/if.h>
|
|
#include <net/if_tun.h>
|
|
#include <netinet/in.h>
|
|
#include <arpa/inet.h>
|
|
|
|
#include <signal.h>
|
|
#include <stdarg.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/time.h>
|
|
#include <termios.h>
|
|
#include <unistd.h>
|
|
|
|
#include "command.h"
|
|
#include "mbuf.h"
|
|
#include "log.h"
|
|
#include "defs.h"
|
|
#include "timer.h"
|
|
#include "fsm.h"
|
|
#include "lcp.h"
|
|
#include "iplist.h"
|
|
#include "throughput.h"
|
|
#include "ipcp.h"
|
|
#include "lcpproto.h"
|
|
#include "bundle.h"
|
|
#include "hdlc.h"
|
|
#include "ccp.h"
|
|
#include "lqr.h"
|
|
#include "phase.h"
|
|
#include "loadalias.h"
|
|
#include "vars.h"
|
|
#include "auth.h"
|
|
#include "pap.h"
|
|
#include "chap.h"
|
|
#include "async.h"
|
|
#include "main.h"
|
|
#include "ip.h"
|
|
#include "modem.h"
|
|
#include "tun.h"
|
|
#include "link.h"
|
|
#include "physical.h"
|
|
|
|
/* for received LQRs */
|
|
struct lqrreq {
|
|
u_char type;
|
|
u_char length;
|
|
u_short proto; /* Quality protocol */
|
|
u_long period; /* Reporting interval */
|
|
};
|
|
|
|
static void LcpLayerUp(struct fsm *);
|
|
static void LcpLayerDown(struct fsm *);
|
|
static void LcpLayerStart(struct fsm *);
|
|
static void LcpLayerFinish(struct fsm *);
|
|
static void LcpInitRestartCounter(struct fsm *);
|
|
static void LcpSendConfigReq(struct fsm *);
|
|
static void LcpSendTerminateReq(struct fsm *);
|
|
static void LcpSendTerminateAck(struct fsm *);
|
|
static void LcpDecodeConfig(struct bundle *, u_char *, int, int);
|
|
|
|
struct lcpstate LcpInfo = {
|
|
{
|
|
"LCP", /* Name of protocol */
|
|
PROTO_LCP, /* Protocol Number */
|
|
LCP_MAXCODE,
|
|
1, /* Open mode delay */
|
|
ST_INITIAL, /* State of machine */
|
|
0, 0, 0,
|
|
{0, 0, 0, NULL, NULL, NULL}, /* FSM timer */
|
|
{0, 0, 0, NULL, NULL, NULL}, /* Open timer */
|
|
{0, 0, 0, NULL, NULL, NULL}, /* Stopped timer */
|
|
LogLCP,
|
|
NULL, /* link */
|
|
NULL, /* bundle */
|
|
LcpLayerUp,
|
|
LcpLayerDown,
|
|
LcpLayerStart,
|
|
LcpLayerFinish,
|
|
LcpInitRestartCounter,
|
|
LcpSendConfigReq,
|
|
LcpSendTerminateReq,
|
|
LcpSendTerminateAck,
|
|
LcpDecodeConfig,
|
|
}
|
|
};
|
|
|
|
static const char *cftypes[] = {
|
|
/* Check out the latest ``Assigned numbers'' rfc (rfc1700.txt) */
|
|
"???",
|
|
"MRU", /* 1: Maximum-Receive-Unit */
|
|
"ACCMAP", /* 2: Async-Control-Character-Map */
|
|
"AUTHPROTO", /* 3: Authentication-Protocol */
|
|
"QUALPROTO", /* 4: Quality-Protocol */
|
|
"MAGICNUM", /* 5: Magic-Number */
|
|
"RESERVED", /* 6: RESERVED */
|
|
"PROTOCOMP", /* 7: Protocol-Field-Compression */
|
|
"ACFCOMP", /* 8: Address-and-Control-Field-Compression */
|
|
"FCSALT", /* 9: FCS-Alternatives */
|
|
"SDP", /* 10: Self-Describing-Pad */
|
|
"NUMMODE", /* 11: Numbered-Mode */
|
|
"MULTIPROC", /* 12: Multi-Link-Procedure */
|
|
"CALLBACK", /* 13: Callback */
|
|
"CONTIME", /* 14: Connect-Time */
|
|
"COMPFRAME", /* 15: Compound-Frames */
|
|
"NDE", /* 16: Nominal-Data-Encapsulation */
|
|
"MULTIMRRU", /* 17: Multilink-MRRU */
|
|
"MULTISSNH", /* 18: Multilink-Short-Sequence-Number-Header */
|
|
"MULTIED", /* 19: Multilink-Endpoint-Descriminator */
|
|
"PROPRIETRY", /* 20: Proprietary */
|
|
"DCEID", /* 21: DCE-Identifier */
|
|
"MULTIPP", /* 22: Multi-Link-Plus-Procedure */
|
|
"LDBACP", /* 23: Link Discriminator for BACP */
|
|
};
|
|
|
|
#define NCFTYPES (sizeof cftypes/sizeof cftypes[0])
|
|
|
|
static void
|
|
LcpReportTime(void *v)
|
|
{
|
|
/* Moan about HDLC errors */
|
|
struct pppTimer *ReportTimer = (struct pppTimer *)v;
|
|
|
|
if (LogIsKept(LogDEBUG)) {
|
|
time_t t = time(NULL);
|
|
LogPrintf(LogDEBUG, "LcpReportTime: %s\n", ctime(&t));
|
|
}
|
|
StopTimer(ReportTimer);
|
|
ReportTimer->state = TIMER_STOPPED;
|
|
StartTimer(ReportTimer);
|
|
HdlcErrorCheck();
|
|
}
|
|
|
|
int
|
|
ReportLcpStatus(struct cmdargs const *arg)
|
|
{
|
|
if (!VarTerm)
|
|
return 1;
|
|
|
|
fprintf(VarTerm, "%s [%s]\n", LcpInfo.fsm.name,
|
|
StateNames[LcpInfo.fsm.state]);
|
|
fprintf(VarTerm,
|
|
" his side: MRU %d, ACCMAP %08lx, PROTOCOMP %d, ACFCOMP %d,\n"
|
|
" MAGIC %08lx, REJECT %04x\n",
|
|
LcpInfo.his_mru, (u_long)LcpInfo.his_accmap, LcpInfo.his_protocomp,
|
|
LcpInfo.his_acfcomp, (u_long)LcpInfo.his_magic, LcpInfo.his_reject);
|
|
fprintf(VarTerm,
|
|
" my side: MRU %d, ACCMAP %08lx, PROTOCOMP %d, ACFCOMP %d,\n"
|
|
" MAGIC %08lx, REJECT %04x\n",
|
|
LcpInfo.want_mru, (u_long)LcpInfo.want_accmap, LcpInfo.want_protocomp,
|
|
LcpInfo.want_acfcomp, (u_long)LcpInfo.want_magic, LcpInfo.my_reject);
|
|
fprintf(VarTerm, "\nDefaults: MRU = %d, ACCMAP = %08lx\t",
|
|
VarMRU, (u_long)VarAccmap);
|
|
fprintf(VarTerm, "Open Mode: %s",
|
|
(VarOpenMode == OPEN_PASSIVE) ? "passive" : "active");
|
|
if (VarOpenMode > 0)
|
|
fprintf(VarTerm, " (delay %d)", VarOpenMode);
|
|
fputc('\n', VarTerm);
|
|
return 0;
|
|
}
|
|
|
|
static u_int32_t
|
|
GenerateMagic(void)
|
|
{
|
|
/* Generate random number which will be used as magic number */
|
|
randinit();
|
|
return (random());
|
|
}
|
|
|
|
void
|
|
LcpInit(struct bundle *bundle, struct physical *physical)
|
|
{
|
|
/* Initialise ourselves */
|
|
FsmInit(&LcpInfo.fsm, bundle, physical2link(physical));
|
|
HdlcInit();
|
|
async_Init(&physical->async);
|
|
|
|
LcpInfo.his_mru = DEF_MRU;
|
|
LcpInfo.his_accmap = 0xffffffff;
|
|
LcpInfo.his_magic = 0;
|
|
LcpInfo.his_lqrperiod = 0;
|
|
LcpInfo.his_protocomp = 0;
|
|
LcpInfo.his_acfcomp = 0;
|
|
LcpInfo.his_auth = 0;
|
|
|
|
LcpInfo.want_mru = VarMRU;
|
|
LcpInfo.want_accmap = VarAccmap;
|
|
LcpInfo.want_magic = GenerateMagic();
|
|
LcpInfo.want_auth = Enabled(ConfChap) ? PROTO_CHAP :
|
|
Enabled(ConfPap) ? PROTO_PAP : 0;
|
|
LcpInfo.want_lqrperiod = Enabled(ConfLqr) ? VarLqrTimeout * 100 : 0;
|
|
LcpInfo.want_protocomp = Enabled(ConfProtocomp) ? 1 : 0;
|
|
LcpInfo.want_acfcomp = Enabled(ConfAcfcomp) ? 1 : 0;
|
|
|
|
LcpInfo.his_reject = LcpInfo.my_reject = 0;
|
|
LcpInfo.auth_iwait = LcpInfo.auth_ineed = 0;
|
|
LcpInfo.LcpFailedMagic = 0;
|
|
memset(&LcpInfo.ReportTimer, '\0', sizeof LcpInfo.ReportTimer);
|
|
LcpInfo.fsm.maxconfig = 10;
|
|
}
|
|
|
|
static void
|
|
LcpInitRestartCounter(struct fsm * fp)
|
|
{
|
|
/* Set fsm timer load */
|
|
fp->FsmTimer.load = VarRetryTimeout * SECTICKS;
|
|
fp->restart = 5;
|
|
}
|
|
|
|
int
|
|
LcpPutConf(int log, u_char *tgt, const struct lcp_opt *o, const char *nm,
|
|
const char *arg, ...)
|
|
{
|
|
va_list ap;
|
|
char buf[30];
|
|
|
|
va_start(ap, arg);
|
|
memcpy(tgt, o, o->len);
|
|
if (arg == NULL || *arg == '\0')
|
|
LogPrintf(log, " %s[%d]\n", nm, o->len);
|
|
else {
|
|
vsnprintf(buf, sizeof buf, arg, ap);
|
|
LogPrintf(log, " %s[%d] %s\n", nm, o->len, buf);
|
|
}
|
|
va_end(ap);
|
|
|
|
return o->len;
|
|
}
|
|
|
|
#define PUTN(ty) \
|
|
do { \
|
|
o.id = ty; \
|
|
o.len = 2; \
|
|
cp += LcpPutConf(LogLCP, cp, &o, cftypes[o.id], NULL); \
|
|
} while (0)
|
|
|
|
#define PUTHEX32(ty, arg) \
|
|
do { \
|
|
o.id = ty; \
|
|
o.len = 6; \
|
|
*(u_long *)o.data = htonl(arg); \
|
|
cp += LcpPutConf(LogLCP, cp, &o, cftypes[o.id], "0x%08lx", (u_long)arg);\
|
|
} while (0)
|
|
|
|
#define PUTACCMAP(arg) PUTHEX32(TY_ACCMAP, arg)
|
|
#define PUTMAGIC(arg) PUTHEX32(TY_MAGICNUM, arg)
|
|
|
|
#define PUTMRU(arg) \
|
|
do { \
|
|
o.id = TY_MRU; \
|
|
o.len = 4; \
|
|
*(u_short *)o.data = htons(arg); \
|
|
cp += LcpPutConf(LogLCP, cp, &o, cftypes[o.id], "%u", arg); \
|
|
} while (0)
|
|
|
|
#define PUTLQR(period) \
|
|
do { \
|
|
o.id = TY_QUALPROTO; \
|
|
o.len = 8; \
|
|
*(u_short *)o.data = htons(PROTO_LQR); \
|
|
*(u_long *)(o.data+2) = htonl(period); \
|
|
cp += LcpPutConf(LogLCP, cp, &o, cftypes[o.id], \
|
|
"period %ld", (u_long)period); \
|
|
} while (0)
|
|
|
|
#define PUTPAP() \
|
|
do { \
|
|
o.id = TY_AUTHPROTO; \
|
|
o.len = 4; \
|
|
*(u_short *)o.data = htons(PROTO_PAP); \
|
|
cp += LcpPutConf(LogLCP, cp, &o, cftypes[o.id], \
|
|
"0x%04x (PAP)", PROTO_PAP); \
|
|
} while (0)
|
|
|
|
#define PUTCHAP(val) \
|
|
do { \
|
|
o.id = TY_AUTHPROTO; \
|
|
o.len = 5; \
|
|
*(u_short *)o.data = htons(PROTO_CHAP); \
|
|
o.data[2] = val; \
|
|
cp += LcpPutConf(LogLCP, cp, &o, cftypes[o.id], \
|
|
"0x%04x (CHAP 0x%02x)", PROTO_CHAP, val); \
|
|
} while (0)
|
|
|
|
#define PUTMD5CHAP() PUTCHAP(0x05)
|
|
#define PUTMSCHAP() PUTCHAP(0x80)
|
|
|
|
static void
|
|
LcpSendConfigReq(struct fsm *fp)
|
|
{
|
|
/* Send config REQ please */
|
|
struct physical *p = link2physical(fp->link);
|
|
u_char *cp;
|
|
struct lcp_opt o;
|
|
|
|
if (!p) {
|
|
LogPrintf(LogERROR, "LcpSendConfigReq: Not a physical link !\n");
|
|
return;
|
|
}
|
|
|
|
LogPrintf(LogLCP, "LcpSendConfigReq\n");
|
|
cp = ReqBuff;
|
|
if (!Physical_IsSync(p)) {
|
|
if (LcpInfo.want_acfcomp && !REJECTED(&LcpInfo, TY_ACFCOMP))
|
|
PUTN(TY_ACFCOMP);
|
|
|
|
if (LcpInfo.want_protocomp && !REJECTED(&LcpInfo, TY_PROTOCOMP))
|
|
PUTN(TY_PROTOCOMP);
|
|
|
|
if (!REJECTED(&LcpInfo, TY_ACCMAP))
|
|
PUTACCMAP(LcpInfo.want_accmap);
|
|
}
|
|
|
|
if (!REJECTED(&LcpInfo, TY_MRU))
|
|
PUTMRU(LcpInfo.want_mru);
|
|
|
|
if (LcpInfo.want_magic && !REJECTED(&LcpInfo, TY_MAGICNUM))
|
|
PUTMAGIC(LcpInfo.want_magic);
|
|
|
|
if (LcpInfo.want_lqrperiod && !REJECTED(&LcpInfo, TY_QUALPROTO))
|
|
PUTLQR(LcpInfo.want_lqrperiod);
|
|
|
|
switch (LcpInfo.want_auth) {
|
|
case PROTO_PAP:
|
|
PUTPAP();
|
|
break;
|
|
|
|
case PROTO_CHAP:
|
|
#ifdef HAVE_DES
|
|
if (VarMSChap)
|
|
PUTMSCHAP(); /* Use MSChap */
|
|
else
|
|
#endif
|
|
PUTMD5CHAP(); /* Use MD5 */
|
|
break;
|
|
}
|
|
FsmOutput(fp, CODE_CONFIGREQ, fp->reqid++, ReqBuff, cp - ReqBuff);
|
|
}
|
|
|
|
void
|
|
LcpSendProtoRej(u_char *option, int count)
|
|
{
|
|
/* Don't understand `option' */
|
|
LogPrintf(LogLCP, "LcpSendProtoRej\n");
|
|
FsmOutput(&LcpInfo.fsm, CODE_PROTOREJ, LcpInfo.fsm.reqid, option, count);
|
|
}
|
|
|
|
static void
|
|
LcpSendTerminateReq(struct fsm * fp)
|
|
{
|
|
/* Term REQ just sent by FSM */
|
|
}
|
|
|
|
static void
|
|
LcpSendTerminateAck(struct fsm * fp)
|
|
{
|
|
/* Send Term ACK please */
|
|
LogPrintf(LogLCP, "LcpSendTerminateAck.\n");
|
|
FsmOutput(fp, CODE_TERMACK, fp->reqid++, NULL, 0);
|
|
}
|
|
|
|
static void
|
|
LcpLayerStart(struct fsm *fp)
|
|
{
|
|
/* We're about to start up ! */
|
|
struct physical *p = link2physical(fp->link);
|
|
|
|
LogPrintf(LogLCP, "LcpLayerStart\n");
|
|
if (p)
|
|
NewPhase(fp->bundle, p, PHASE_ESTABLISH);
|
|
else
|
|
LogPrintf(LogERROR, "LcpLayerStart: Not a physical link !\n");
|
|
}
|
|
|
|
static void
|
|
StopAllTimers(void)
|
|
{
|
|
StopTimer(&LcpInfo.ReportTimer);
|
|
StopIdleTimer();
|
|
StopTimer(&AuthPapInfo.authtimer);
|
|
StopTimer(&AuthChapInfo.authtimer);
|
|
StopLqrTimer();
|
|
}
|
|
|
|
static void
|
|
LcpLayerFinish(struct fsm *fp)
|
|
{
|
|
/* We're now down */
|
|
struct physical *p = link2physical(fp->link);
|
|
|
|
LogPrintf(LogLCP, "LcpLayerFinish\n");
|
|
LcpInfo.LcpFailedMagic = 0;
|
|
link_Close(fp->link, 0);
|
|
StopAllTimers();
|
|
CcpInfo.fsm.restart = 0;
|
|
IpcpInfo.fsm.restart = 0;
|
|
|
|
/* We're down at last. Lets tell background and direct mode to get out */
|
|
if (p)
|
|
NewPhase(fp->bundle, p, PHASE_DEAD);
|
|
else
|
|
LogPrintf(LogERROR, "LcpLayerFinish: Not a physical link !\n");
|
|
Prompt();
|
|
}
|
|
|
|
static void
|
|
LcpLayerUp(struct fsm *fp)
|
|
{
|
|
/* We're now up */
|
|
struct physical *p = link2physical(fp->link);
|
|
|
|
LogPrintf(LogLCP, "LcpLayerUp\n");
|
|
|
|
if (p) {
|
|
async_SetLinkParams(&p->async, &LcpInfo);
|
|
NewPhase(fp->bundle, p, PHASE_AUTHENTICATE);
|
|
StartLqm(p);
|
|
} else
|
|
LogPrintf(LogERROR, "LcpLayerUp: Not a physical link !\n");
|
|
|
|
StopTimer(&LcpInfo.ReportTimer);
|
|
LcpInfo.ReportTimer.state = TIMER_STOPPED;
|
|
LcpInfo.ReportTimer.load = 60 * SECTICKS;
|
|
LcpInfo.ReportTimer.arg = &LcpInfo.ReportTimer;
|
|
LcpInfo.ReportTimer.func = LcpReportTime;
|
|
StartTimer(&LcpInfo.ReportTimer);
|
|
}
|
|
|
|
static void
|
|
LcpLayerDown(struct fsm *fp)
|
|
{
|
|
/* About to come down */
|
|
bundle_Linkdown(fp->bundle);
|
|
|
|
LogPrintf(LogLCP, "LcpLayerDown\n");
|
|
/*
|
|
* bundle_Linkdown() brings CCP & IPCP down, then waits 'till we go from
|
|
* STOPPING to STOPPED. At this point, the FSM gives us a LayerFinish
|
|
*/
|
|
}
|
|
|
|
void
|
|
LcpUp()
|
|
{
|
|
/* Lower layers are ready.... go */
|
|
LcpInfo.LcpFailedMagic = 0;
|
|
FsmUp(&LcpInfo.fsm);
|
|
}
|
|
|
|
void
|
|
LcpDown()
|
|
{
|
|
/* Physical link is gone - sudden death */
|
|
CcpDown(); /* CCP must come down */
|
|
IpcpDown(); /* IPCP must come down */
|
|
FsmDown(&LcpInfo.fsm);
|
|
/* FsmDown() results in a LcpLayerDown() if we're currently open. */
|
|
LcpLayerFinish(&LcpInfo.fsm);
|
|
}
|
|
|
|
void
|
|
LcpOpen(int open_mode)
|
|
{
|
|
/* Start LCP please (with the given open_mode) */
|
|
LcpInfo.fsm.open_mode = open_mode;
|
|
LcpInfo.LcpFailedMagic = 0;
|
|
FsmOpen(&LcpInfo.fsm);
|
|
}
|
|
|
|
void
|
|
LcpClose(struct fsm *fp)
|
|
{
|
|
/* Stop LCP please */
|
|
struct physical *p = link2physical(fp->link);
|
|
|
|
if (p)
|
|
NewPhase(fp->bundle, p, PHASE_TERMINATE);
|
|
else
|
|
LogPrintf(LogERROR, "LcpClose: Not a physical link !\n");
|
|
|
|
bundle_Linkdown(fp->bundle);
|
|
if (!(mode & MODE_DAEMON))
|
|
bundle_InterfaceDown(fp->bundle);
|
|
FsmClose(fp);
|
|
}
|
|
|
|
static void
|
|
LcpDecodeConfig(struct bundle *bundle, u_char *cp, int plen, int mode_type)
|
|
{
|
|
/* Deal with incoming PROTO_LCP */
|
|
int type, length, sz, pos;
|
|
u_int32_t *lp, magic, accmap;
|
|
u_short mtu, mru, *sp, proto;
|
|
struct lqrreq *req;
|
|
char request[20], desc[22];
|
|
|
|
ackp = AckBuff;
|
|
nakp = NakBuff;
|
|
rejp = RejBuff;
|
|
|
|
while (plen >= sizeof(struct fsmconfig)) {
|
|
type = *cp;
|
|
length = cp[1];
|
|
|
|
if (type < 0 || type >= NCFTYPES)
|
|
snprintf(request, sizeof request, " <%d>[%d]", type, length);
|
|
else
|
|
snprintf(request, sizeof request, " %s[%d]", cftypes[type], length);
|
|
|
|
switch (type) {
|
|
case TY_MRU:
|
|
sp = (u_short *) (cp + 2);
|
|
mru = htons(*sp);
|
|
LogPrintf(LogLCP, "%s %d\n", request, mru);
|
|
|
|
switch (mode_type) {
|
|
case MODE_REQ:
|
|
mtu = VarPrefMTU;
|
|
if (mtu == 0)
|
|
mtu = MAX_MTU;
|
|
if (mru > mtu) {
|
|
*sp = htons(mtu);
|
|
memcpy(nakp, cp, 4);
|
|
nakp += 4;
|
|
} else if (mru < MIN_MRU) {
|
|
*sp = htons(MIN_MRU);
|
|
memcpy(nakp, cp, 4);
|
|
nakp += 4;
|
|
} else {
|
|
LcpInfo.his_mru = mru;
|
|
memcpy(ackp, cp, 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_int32_t *) (cp + 2);
|
|
accmap = htonl(*lp);
|
|
LogPrintf(LogLCP, "%s 0x%08lx\n", request, (u_long)accmap);
|
|
|
|
switch (mode_type) {
|
|
case MODE_REQ:
|
|
LcpInfo.his_accmap = accmap;
|
|
memcpy(ackp, cp, 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);
|
|
switch (proto) {
|
|
case PROTO_PAP:
|
|
LogPrintf(LogLCP, "%s 0x%04x (PAP)\n", request, proto);
|
|
break;
|
|
case PROTO_CHAP:
|
|
LogPrintf(LogLCP, "%s 0x%04x (CHAP 0x%02x)\n", request, proto, cp[4]);
|
|
break;
|
|
default:
|
|
LogPrintf(LogLCP, "%s 0x%04x\n", request, proto);
|
|
break;
|
|
}
|
|
|
|
switch (mode_type) {
|
|
case MODE_REQ:
|
|
switch (proto) {
|
|
case PROTO_PAP:
|
|
if (length != 4) {
|
|
LogPrintf(LogLCP, " Bad length!\n");
|
|
goto reqreject;
|
|
}
|
|
if (Acceptable(ConfPap)) {
|
|
LcpInfo.his_auth = proto;
|
|
memcpy(ackp, cp, length);
|
|
ackp += length;
|
|
} else if (Acceptable(ConfChap)) {
|
|
*nakp++ = *cp;
|
|
*nakp++ = 5;
|
|
*nakp++ = (unsigned char) (PROTO_CHAP >> 8);
|
|
*nakp++ = (unsigned char) PROTO_CHAP;
|
|
#ifdef HAVE_DES
|
|
if (VarMSChap)
|
|
*nakp++ = 0x80;
|
|
else
|
|
#endif
|
|
*nakp++ = 5;
|
|
} else
|
|
goto reqreject;
|
|
break;
|
|
|
|
case PROTO_CHAP:
|
|
if (length < 5) {
|
|
LogPrintf(LogLCP, " Bad length!\n");
|
|
goto reqreject;
|
|
}
|
|
#ifdef HAVE_DES
|
|
if (Acceptable(ConfChap) && (cp[4] == 5 || cp[4] == 0x80))
|
|
#else
|
|
if (Acceptable(ConfChap) && cp[4] == 5)
|
|
#endif
|
|
{
|
|
LcpInfo.his_auth = proto;
|
|
memcpy(ackp, cp, length);
|
|
ackp += length;
|
|
#ifdef HAVE_DES
|
|
VarMSChap = cp[4] == 0x80;
|
|
#endif
|
|
} 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(LogLCP, "%s 0x%04x - not recognised, NAK\n",
|
|
request, proto);
|
|
memcpy(nakp, cp, length);
|
|
nakp += length;
|
|
break;
|
|
}
|
|
break;
|
|
case MODE_NAK:
|
|
switch (proto) {
|
|
case PROTO_PAP:
|
|
if (Enabled(ConfPap))
|
|
LcpInfo.want_auth = PROTO_PAP;
|
|
else {
|
|
LogPrintf(LogLCP, "Peer will only send PAP (not enabled)\n");
|
|
LcpInfo.his_reject |= (1 << type);
|
|
}
|
|
break;
|
|
case PROTO_CHAP:
|
|
if (Enabled(ConfChap))
|
|
LcpInfo.want_auth = PROTO_CHAP;
|
|
else {
|
|
LogPrintf(LogLCP, "Peer will only send CHAP (not enabled)\n");
|
|
LcpInfo.his_reject |= (1 << type);
|
|
}
|
|
break;
|
|
default:
|
|
/* We've been NAK'd with something we don't understand :-( */
|
|
LcpInfo.his_reject |= (1 << type);
|
|
break;
|
|
}
|
|
break;
|
|
case MODE_REJ:
|
|
LcpInfo.his_reject |= (1 << type);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case TY_QUALPROTO:
|
|
req = (struct lqrreq *)cp;
|
|
LogPrintf(LogLCP, "%s proto %x, interval %dms\n",
|
|
request, ntohs(req->proto), ntohl(req->period) * 10);
|
|
switch (mode_type) {
|
|
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);
|
|
memcpy(ackp, cp, length);
|
|
ackp += length;
|
|
}
|
|
break;
|
|
case MODE_NAK:
|
|
break;
|
|
case MODE_REJ:
|
|
LcpInfo.his_reject |= (1 << type);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case TY_MAGICNUM:
|
|
lp = (u_int32_t *) (cp + 2);
|
|
magic = ntohl(*lp);
|
|
LogPrintf(LogLCP, "%s 0x%08lx\n", request, (u_long)magic);
|
|
|
|
switch (mode_type) {
|
|
case MODE_REQ:
|
|
if (LcpInfo.want_magic) {
|
|
/* Validate magic number */
|
|
if (magic == LcpInfo.want_magic) {
|
|
LogPrintf(LogLCP, "Magic is same (%08lx) - %d times\n",
|
|
(u_long)magic, ++LcpInfo.LcpFailedMagic);
|
|
LcpInfo.want_magic = GenerateMagic();
|
|
memcpy(nakp, cp, 6);
|
|
nakp += 6;
|
|
ualarm(TICKUNIT * (4 + 4 * LcpInfo.LcpFailedMagic), 0);
|
|
sigpause(0);
|
|
} else {
|
|
LcpInfo.his_magic = magic;
|
|
memcpy(ackp, cp, length);
|
|
ackp += length;
|
|
LcpInfo.LcpFailedMagic = 0;
|
|
}
|
|
} else {
|
|
LcpInfo.my_reject |= (1 << type);
|
|
goto reqreject;
|
|
}
|
|
break;
|
|
case MODE_NAK:
|
|
LogPrintf(LogLCP, " Magic 0x%08lx is NAKed!\n", (u_long)magic);
|
|
LcpInfo.want_magic = GenerateMagic();
|
|
break;
|
|
case MODE_REJ:
|
|
LogPrintf(LogLCP, " Magic 0x%80x is REJected!\n", magic);
|
|
LcpInfo.want_magic = 0;
|
|
LcpInfo.his_reject |= (1 << type);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case TY_PROTOCOMP:
|
|
LogPrintf(LogLCP, "%s\n", request);
|
|
|
|
switch (mode_type) {
|
|
case MODE_REQ:
|
|
if (Acceptable(ConfProtocomp)) {
|
|
LcpInfo.his_protocomp = 1;
|
|
memcpy(ackp, cp, 2);
|
|
ackp += 2;
|
|
} else {
|
|
#ifdef OLDMST
|
|
/*
|
|
* MorningStar before v1.3 needs NAK
|
|
*/
|
|
memcpy(nakp, cp, 2);
|
|
nakp += 2;
|
|
#else
|
|
memcpy(rejp, cp, 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(LogLCP, "%s\n", request);
|
|
switch (mode_type) {
|
|
case MODE_REQ:
|
|
if (Acceptable(ConfAcfcomp)) {
|
|
LcpInfo.his_acfcomp = 1;
|
|
memcpy(ackp, cp, 2);
|
|
ackp += 2;
|
|
} else {
|
|
#ifdef OLDMST
|
|
/*
|
|
* MorningStar before v1.3 needs NAK
|
|
*/
|
|
memcpy(nakp, cp, 2);
|
|
nakp += 2;
|
|
#else
|
|
memcpy(rejp, cp, 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(LogLCP, "%s\n", request);
|
|
switch (mode_type) {
|
|
case MODE_REQ:
|
|
case MODE_NAK:
|
|
case MODE_REJ:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
sz = (sizeof desc - 2) / 2;
|
|
if (sz > length - 2)
|
|
sz = length - 2;
|
|
pos = 0;
|
|
desc[0] = sz ? ' ' : '\0';
|
|
for (pos = 0; sz--; pos++)
|
|
sprintf(desc+(pos<<1)+1, "%02x", cp[pos+2]);
|
|
|
|
LogPrintf(LogLCP, "%s%s\n", request, desc);
|
|
|
|
if (mode_type == MODE_REQ) {
|
|
reqreject:
|
|
if (length > sizeof RejBuff - (rejp - RejBuff)) {
|
|
length = sizeof RejBuff - (rejp - RejBuff);
|
|
LogPrintf(LogLCP, "Can't REJ length %d - trunating to %d\n",
|
|
cp[1], length);
|
|
}
|
|
memcpy(rejp, cp, length);
|
|
rejp += length;
|
|
LcpInfo.my_reject |= (1 << type);
|
|
if (length != cp[1])
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
/* to avoid inf. loop */
|
|
if (length == 0) {
|
|
LogPrintf(LogLCP, "LCP size zero\n");
|
|
break;
|
|
}
|
|
plen -= length;
|
|
cp += length;
|
|
}
|
|
}
|
|
|
|
void
|
|
LcpInput(struct mbuf * bp)
|
|
{
|
|
/* Got PROTO_LCP from link */
|
|
FsmInput(&LcpInfo.fsm, bp);
|
|
}
|