1998-01-29 00:44:16 +00:00
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*
|
1998-01-31 02:48:30 +00:00
|
|
|
* $Id: lcp.c,v 1.55.2.4 1998/01/30 19:45:47 brian Exp $
|
1998-01-29 00:44:16 +00:00
|
|
|
*
|
|
|
|
* 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"
|
1998-01-29 23:11:44 +00:00
|
|
|
#include "iplist.h"
|
|
|
|
#include "throughput.h"
|
1998-01-29 00:44:16 +00:00
|
|
|
#include "ipcp.h"
|
|
|
|
#include "lcpproto.h"
|
|
|
|
#include "os.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"
|
1998-01-30 19:46:07 +00:00
|
|
|
#include "link.h"
|
1998-01-29 00:49:32 +00:00
|
|
|
#include "physical.h"
|
1998-01-29 00:44:16 +00:00
|
|
|
|
|
|
|
/* 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 *);
|
1998-01-31 02:48:30 +00:00
|
|
|
static void LcpInitRestartCounter(struct fsm *);
|
|
|
|
static void LcpSendConfigReq(struct fsm *);
|
|
|
|
static void LcpSendTerminateReq(struct fsm *);
|
|
|
|
static void LcpSendTerminateAck(struct fsm *);
|
|
|
|
static void LcpDecodeConfig(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,
|
|
|
|
LcpLayerUp,
|
|
|
|
LcpLayerDown,
|
|
|
|
LcpLayerStart,
|
|
|
|
LcpLayerFinish,
|
|
|
|
LcpInitRestartCounter,
|
|
|
|
LcpSendConfigReq,
|
|
|
|
LcpSendTerminateReq,
|
|
|
|
LcpSendTerminateAck,
|
|
|
|
LcpDecodeConfig,
|
|
|
|
}
|
|
|
|
};
|
1998-01-29 00:44:16 +00:00
|
|
|
|
|
|
|
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
|
1998-01-31 02:48:30 +00:00
|
|
|
LcpReportTime(void *v)
|
1998-01-29 00:44:16 +00:00
|
|
|
{
|
1998-01-31 02:48:30 +00:00
|
|
|
/* Moan about HDLC errors */
|
|
|
|
struct pppTimer *ReportTimer = (struct pppTimer *)v;
|
1998-01-30 01:33:46 +00:00
|
|
|
|
1998-01-29 00:44:16 +00:00
|
|
|
if (LogIsKept(LogDEBUG)) {
|
1998-01-31 02:48:30 +00:00
|
|
|
time_t t = time(NULL);
|
1998-01-29 00:44:16 +00:00
|
|
|
LogPrintf(LogDEBUG, "LcpReportTime: %s\n", ctime(&t));
|
|
|
|
}
|
1998-01-31 02:48:30 +00:00
|
|
|
StopTimer(ReportTimer);
|
|
|
|
ReportTimer->state = TIMER_STOPPED;
|
|
|
|
StartTimer(ReportTimer);
|
1998-01-29 00:44:16 +00:00
|
|
|
HdlcErrorCheck();
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
ReportLcpStatus(struct cmdargs const *arg)
|
|
|
|
{
|
|
|
|
if (!VarTerm)
|
|
|
|
return 1;
|
|
|
|
|
1998-01-31 02:48:30 +00:00
|
|
|
fprintf(VarTerm, "%s [%s]\n", LcpInfo.fsm.name,
|
|
|
|
StateNames[LcpInfo.fsm.state]);
|
1998-01-29 00:44:16 +00:00
|
|
|
fprintf(VarTerm,
|
|
|
|
" his side: MRU %d, ACCMAP %08lx, PROTOCOMP %d, ACFCOMP %d,\n"
|
|
|
|
" MAGIC %08lx, REJECT %04x\n",
|
1998-01-30 01:33:46 +00:00
|
|
|
LcpInfo.his_mru, (u_long)LcpInfo.his_accmap, LcpInfo.his_protocomp,
|
|
|
|
LcpInfo.his_acfcomp, (u_long)LcpInfo.his_magic, LcpInfo.his_reject);
|
1998-01-29 00:44:16 +00:00
|
|
|
fprintf(VarTerm,
|
|
|
|
" my side: MRU %d, ACCMAP %08lx, PROTOCOMP %d, ACFCOMP %d,\n"
|
|
|
|
" MAGIC %08lx, REJECT %04x\n",
|
1998-01-30 01:33:46 +00:00
|
|
|
LcpInfo.want_mru, (u_long)LcpInfo.want_accmap, LcpInfo.want_protocomp,
|
|
|
|
LcpInfo.want_acfcomp, (u_long)LcpInfo.want_magic, LcpInfo.my_reject);
|
1998-01-29 00:44:16 +00:00
|
|
|
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)
|
|
|
|
{
|
1998-01-31 02:48:30 +00:00
|
|
|
/* Generate random number which will be used as magic number */
|
1998-01-29 00:44:16 +00:00
|
|
|
randinit();
|
|
|
|
return (random());
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
1998-01-29 00:49:32 +00:00
|
|
|
LcpInit(struct physical *physical)
|
1998-01-29 00:44:16 +00:00
|
|
|
{
|
1998-01-31 02:48:30 +00:00
|
|
|
/* Initialise ourselves */
|
|
|
|
FsmInit(&LcpInfo.fsm, physical2link(physical));
|
1998-01-29 00:44:16 +00:00
|
|
|
HdlcInit();
|
1998-01-31 02:48:30 +00:00
|
|
|
|
1998-01-30 01:33:46 +00:00
|
|
|
LcpInfo.his_mru = DEF_MRU;
|
|
|
|
LcpInfo.his_accmap = 0xffffffff;
|
1998-01-31 02:48:30 +00:00
|
|
|
LcpInfo.his_magic = 0;
|
|
|
|
LcpInfo.his_lqrperiod = 0;
|
|
|
|
LcpInfo.his_protocomp = 0;
|
|
|
|
LcpInfo.his_acfcomp = 0;
|
|
|
|
LcpInfo.his_auth = 0;
|
|
|
|
|
|
|
|
LcpInfo.want_mru = VarMRU;
|
1998-01-30 01:33:46 +00:00
|
|
|
LcpInfo.want_accmap = VarAccmap;
|
|
|
|
LcpInfo.want_magic = GenerateMagic();
|
1998-01-31 02:48:30 +00:00
|
|
|
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;
|
1998-01-29 00:44:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
LcpInitRestartCounter(struct fsm * fp)
|
|
|
|
{
|
1998-01-31 02:48:30 +00:00
|
|
|
/* Set fsm timer load */
|
1998-01-29 00:44:16 +00:00
|
|
|
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
|
1998-01-30 19:46:07 +00:00
|
|
|
LcpSendConfigReq(struct fsm *fp)
|
1998-01-29 00:44:16 +00:00
|
|
|
{
|
1998-01-31 02:48:30 +00:00
|
|
|
/* Send config REQ please */
|
1998-01-30 19:46:07 +00:00
|
|
|
struct physical *p = link2physical(fp->link);
|
1998-01-29 00:44:16 +00:00
|
|
|
u_char *cp;
|
|
|
|
struct lcp_opt o;
|
|
|
|
|
1998-01-30 19:46:07 +00:00
|
|
|
if (!p) {
|
|
|
|
LogPrintf(LogERROR, "LcpSendConfigReq: Not a physical link !\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
1998-01-29 00:44:16 +00:00
|
|
|
LogPrintf(LogLCP, "LcpSendConfigReq\n");
|
|
|
|
cp = ReqBuff;
|
1998-01-30 19:46:07 +00:00
|
|
|
if (!Physical_IsSync(p)) {
|
1998-01-30 01:33:46 +00:00
|
|
|
if (LcpInfo.want_acfcomp && !REJECTED(&LcpInfo, TY_ACFCOMP))
|
1998-01-29 00:44:16 +00:00
|
|
|
PUTN(TY_ACFCOMP);
|
|
|
|
|
1998-01-30 01:33:46 +00:00
|
|
|
if (LcpInfo.want_protocomp && !REJECTED(&LcpInfo, TY_PROTOCOMP))
|
1998-01-29 00:44:16 +00:00
|
|
|
PUTN(TY_PROTOCOMP);
|
|
|
|
|
1998-01-30 01:33:46 +00:00
|
|
|
if (!REJECTED(&LcpInfo, TY_ACCMAP))
|
|
|
|
PUTACCMAP(LcpInfo.want_accmap);
|
1998-01-29 00:44:16 +00:00
|
|
|
}
|
|
|
|
|
1998-01-30 01:33:46 +00:00
|
|
|
if (!REJECTED(&LcpInfo, TY_MRU))
|
|
|
|
PUTMRU(LcpInfo.want_mru);
|
1998-01-29 00:44:16 +00:00
|
|
|
|
1998-01-30 01:33:46 +00:00
|
|
|
if (LcpInfo.want_magic && !REJECTED(&LcpInfo, TY_MAGICNUM))
|
|
|
|
PUTMAGIC(LcpInfo.want_magic);
|
1998-01-29 00:44:16 +00:00
|
|
|
|
1998-01-30 01:33:46 +00:00
|
|
|
if (LcpInfo.want_lqrperiod && !REJECTED(&LcpInfo, TY_QUALPROTO))
|
|
|
|
PUTLQR(LcpInfo.want_lqrperiod);
|
1998-01-29 00:44:16 +00:00
|
|
|
|
1998-01-30 01:33:46 +00:00
|
|
|
switch (LcpInfo.want_auth) {
|
1998-01-29 00:44:16 +00:00
|
|
|
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
|
1998-01-31 02:48:30 +00:00
|
|
|
LcpSendProtoRej(u_char *option, int count)
|
1998-01-29 00:44:16 +00:00
|
|
|
{
|
1998-01-31 02:48:30 +00:00
|
|
|
/* Don't understand `option' */
|
1998-01-29 00:44:16 +00:00
|
|
|
LogPrintf(LogLCP, "LcpSendProtoRej\n");
|
1998-01-31 02:48:30 +00:00
|
|
|
FsmOutput(&LcpInfo.fsm, CODE_PROTOREJ, LcpInfo.fsm.reqid, option, count);
|
1998-01-29 00:44:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
LcpSendTerminateReq(struct fsm * fp)
|
|
|
|
{
|
1998-01-31 02:48:30 +00:00
|
|
|
/* Term REQ just sent by FSM */
|
1998-01-29 00:44:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
LcpSendTerminateAck(struct fsm * fp)
|
|
|
|
{
|
1998-01-31 02:48:30 +00:00
|
|
|
/* Send Term ACK please */
|
1998-01-29 00:44:16 +00:00
|
|
|
LogPrintf(LogLCP, "LcpSendTerminateAck.\n");
|
|
|
|
FsmOutput(fp, CODE_TERMACK, fp->reqid++, NULL, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
1998-01-30 19:46:07 +00:00
|
|
|
LcpLayerStart(struct fsm *fp)
|
1998-01-29 00:44:16 +00:00
|
|
|
{
|
1998-01-31 02:48:30 +00:00
|
|
|
/* We're about to start up ! */
|
1998-01-30 19:46:07 +00:00
|
|
|
struct physical *p = link2physical(fp->link);
|
|
|
|
|
1998-01-29 00:44:16 +00:00
|
|
|
LogPrintf(LogLCP, "LcpLayerStart\n");
|
1998-01-30 19:46:07 +00:00
|
|
|
if (p)
|
|
|
|
NewPhase(p, PHASE_ESTABLISH);
|
|
|
|
else
|
|
|
|
LogPrintf(LogERROR, "LcpLayerStart: Not a physical link !\n");
|
1998-01-29 00:44:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
StopAllTimers(void)
|
|
|
|
{
|
1998-01-30 01:33:46 +00:00
|
|
|
StopTimer(&LcpInfo.ReportTimer);
|
1998-01-29 00:44:16 +00:00
|
|
|
StopIdleTimer();
|
|
|
|
StopTimer(&AuthPapInfo.authtimer);
|
|
|
|
StopTimer(&AuthChapInfo.authtimer);
|
|
|
|
StopLqrTimer();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
1998-01-30 19:46:07 +00:00
|
|
|
LcpLayerFinish(struct fsm *fp)
|
1998-01-29 00:44:16 +00:00
|
|
|
{
|
1998-01-31 02:48:30 +00:00
|
|
|
/* We're now down */
|
1998-01-30 19:46:07 +00:00
|
|
|
struct physical *p = link2physical(fp->link);
|
|
|
|
|
1998-01-29 00:44:16 +00:00
|
|
|
LogPrintf(LogLCP, "LcpLayerFinish\n");
|
1998-01-31 02:48:30 +00:00
|
|
|
LcpInfo.LcpFailedMagic = 0;
|
1998-01-30 19:46:07 +00:00
|
|
|
link_Close(fp->link, 0);
|
1998-01-29 00:44:16 +00:00
|
|
|
StopAllTimers();
|
1998-01-31 02:48:30 +00:00
|
|
|
CcpInfo.fsm.restart = 0;
|
|
|
|
IpcpInfo.fsm.restart = 0;
|
|
|
|
|
1998-01-29 00:44:16 +00:00
|
|
|
/* We're down at last. Lets tell background and direct mode to get out */
|
1998-01-31 02:48:30 +00:00
|
|
|
if (p)
|
1998-01-30 19:46:07 +00:00
|
|
|
NewPhase(p, PHASE_DEAD);
|
1998-01-31 02:48:30 +00:00
|
|
|
else
|
1998-01-30 19:46:07 +00:00
|
|
|
LogPrintf(LogERROR, "LcpLayerFinish: Not a physical link !\n");
|
1998-01-29 00:44:16 +00:00
|
|
|
Prompt();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
1998-01-30 19:46:07 +00:00
|
|
|
LcpLayerUp(struct fsm *fp)
|
1998-01-29 00:44:16 +00:00
|
|
|
{
|
1998-01-31 02:48:30 +00:00
|
|
|
/* We're now up */
|
1998-01-30 19:46:07 +00:00
|
|
|
struct physical *p = link2physical(fp->link);
|
|
|
|
|
1998-01-29 00:44:16 +00:00
|
|
|
LogPrintf(LogLCP, "LcpLayerUp\n");
|
|
|
|
SetLinkParams(&LcpInfo);
|
|
|
|
|
1998-01-30 19:46:07 +00:00
|
|
|
if (p) {
|
|
|
|
NewPhase(p, PHASE_AUTHENTICATE);
|
|
|
|
StartLqm(p);
|
|
|
|
} else
|
|
|
|
LogPrintf(LogERROR, "LcpLayerUp: Not a physical link !\n");
|
1998-01-29 00:44:16 +00:00
|
|
|
|
1998-01-30 01:33:46 +00:00
|
|
|
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);
|
1998-01-29 00:44:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
LcpLayerDown(struct fsm * fp)
|
|
|
|
{
|
1998-01-31 02:48:30 +00:00
|
|
|
/* About to come down */
|
1998-01-29 00:44:16 +00:00
|
|
|
OsLinkdown();
|
1998-01-31 02:48:30 +00:00
|
|
|
|
1998-01-29 00:44:16 +00:00
|
|
|
LogPrintf(LogLCP, "LcpLayerDown\n");
|
|
|
|
/*
|
|
|
|
* OsLinkdown() brings CCP & IPCP down, then waits 'till we go from
|
|
|
|
* STOPPING to STOPPED. At this point, the FSM gives us a LayerFinish
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
LcpUp()
|
|
|
|
{
|
1998-01-31 02:48:30 +00:00
|
|
|
/* Lower layers are ready.... go */
|
1998-01-30 01:33:46 +00:00
|
|
|
LcpInfo.LcpFailedMagic = 0;
|
1998-01-31 02:48:30 +00:00
|
|
|
FsmUp(&LcpInfo.fsm);
|
1998-01-29 00:44:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
LcpDown()
|
1998-01-31 02:48:30 +00:00
|
|
|
{
|
|
|
|
/* Physical link is gone - sudden death */
|
|
|
|
CcpDown(); /* CCP must come down */
|
|
|
|
IpcpDown(); /* IPCP must come down */
|
|
|
|
FsmDown(&LcpInfo.fsm);
|
1998-01-29 00:44:16 +00:00
|
|
|
/* FsmDown() results in a LcpLayerDown() if we're currently open. */
|
1998-01-31 02:48:30 +00:00
|
|
|
LcpLayerFinish(&LcpInfo.fsm);
|
1998-01-29 00:44:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
LcpOpen(int open_mode)
|
|
|
|
{
|
1998-01-31 02:48:30 +00:00
|
|
|
/* Start LCP please (with the given open_mode) */
|
|
|
|
LcpInfo.fsm.open_mode = open_mode;
|
1998-01-30 01:33:46 +00:00
|
|
|
LcpInfo.LcpFailedMagic = 0;
|
1998-01-31 02:48:30 +00:00
|
|
|
FsmOpen(&LcpInfo.fsm);
|
1998-01-29 00:44:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
1998-01-29 00:49:32 +00:00
|
|
|
LcpClose(struct fsm *fp)
|
1998-01-29 00:44:16 +00:00
|
|
|
{
|
1998-01-31 02:48:30 +00:00
|
|
|
/* Stop LCP please */
|
1998-01-30 19:46:07 +00:00
|
|
|
struct physical *p = link2physical(fp->link);
|
|
|
|
|
|
|
|
if (p)
|
|
|
|
NewPhase(p, PHASE_TERMINATE);
|
|
|
|
else
|
|
|
|
LogPrintf(LogERROR, "LcpClose: Not a physical link !\n");
|
|
|
|
|
1998-01-29 00:44:16 +00:00
|
|
|
OsInterfaceDown(0);
|
1998-01-29 00:49:32 +00:00
|
|
|
FsmClose(fp);
|
1998-01-29 00:44:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
LcpDecodeConfig(u_char *cp, int plen, int mode_type)
|
|
|
|
{
|
1998-01-31 02:48:30 +00:00
|
|
|
/* Deal with incoming PROTO_LCP */
|
1998-01-29 00:44:16 +00:00
|
|
|
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:
|
1998-01-31 02:48:30 +00:00
|
|
|
req = (struct lqrreq *)cp;
|
1998-01-29 00:44:16 +00:00
|
|
|
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",
|
1998-01-30 01:33:46 +00:00
|
|
|
(u_long)magic, ++LcpInfo.LcpFailedMagic);
|
1998-01-29 00:44:16 +00:00
|
|
|
LcpInfo.want_magic = GenerateMagic();
|
|
|
|
memcpy(nakp, cp, 6);
|
|
|
|
nakp += 6;
|
1998-01-30 01:33:46 +00:00
|
|
|
ualarm(TICKUNIT * (4 + 4 * LcpInfo.LcpFailedMagic), 0);
|
1998-01-29 00:44:16 +00:00
|
|
|
sigpause(0);
|
|
|
|
} else {
|
|
|
|
LcpInfo.his_magic = magic;
|
|
|
|
memcpy(ackp, cp, length);
|
|
|
|
ackp += length;
|
1998-01-30 01:33:46 +00:00
|
|
|
LcpInfo.LcpFailedMagic = 0;
|
1998-01-29 00:44:16 +00:00
|
|
|
}
|
|
|
|
} 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)
|
|
|
|
{
|
1998-01-31 02:48:30 +00:00
|
|
|
/* Got PROTO_LCP from link */
|
|
|
|
FsmInput(&LcpInfo.fsm, bp);
|
1998-01-29 00:44:16 +00:00
|
|
|
}
|