lcp.c revision 28461
162607Sitojun/*
262607Sitojun *	      PPP Link Control Protocol (LCP) Module
355163Sshin *
455163Sshin *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
555163Sshin *
655163Sshin *   Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
762607Sitojun *
855163Sshin * Redistribution and use in source and binary forms are permitted
955163Sshin * provided that the above copyright notice and this paragraph are
1055163Sshin * duplicated in all such forms and that any documentation,
1155163Sshin * advertising materials, and other materials related to such
1255163Sshin * distribution and use acknowledge that the software was developed
1355163Sshin * by the Internet Initiative Japan, Inc.  The name of the
1455163Sshin * IIJ may not be used to endorse or promote products derived
1555163Sshin * from this software without specific prior written permission.
1655163Sshin * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1755163Sshin * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1855163Sshin * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1962607Sitojun *
2055163Sshin * $Id: lcp.c,v 1.25 1997/08/01 02:02:28 brian Exp $
2155163Sshin *
2255163Sshin * TODO:
2355163Sshin *      o Validate magic number received from peer.
2455163Sshin *	o Limit data field length by MRU
2555163Sshin */
2655163Sshin#include <sys/time.h>
2755163Sshin#include "fsm.h"
2855163Sshin#include "lcp.h"
2955163Sshin#include "ipcp.h"
3055163Sshin#include "lcpproto.h"
3155163Sshin#include "os.h"
3255163Sshin#include "hdlc.h"
3355163Sshin#include "ccp.h"
3462607Sitojun#include "lqr.h"
3555163Sshin#include "phase.h"
3655163Sshin#include "loadalias.h"
3755163Sshin#include "vars.h"
3855163Sshin#include "auth.h"
3955163Sshin#include <arpa/inet.h>
4055163Sshin
4155163Sshinextern void IpcpUp();
4255163Sshinextern void IpcpOpen();
4355163Sshinextern void SetLinkParams(struct lcpstate *);
4455163Sshinextern void Prompt();
4555163Sshinextern void StopIdleTimer();
4655163Sshinextern void OsLinkdown();
4755163Sshinextern void Cleanup();
4855163Sshinextern struct pppTimer IpcpReportTimer;
4955163Sshinextern int randinit;
5055163Sshin
5162607Sitojunstruct lcpstate LcpInfo;
5255163Sshin
5355163Sshinstatic void LcpSendConfigReq(struct fsm *);
5455163Sshinstatic void LcpSendTerminateReq(struct fsm *fp);
5555163Sshinstatic void LcpSendTerminateAck(struct fsm *fp);
5655163Sshinstatic void LcpDecodeConfig(u_char *cp, int flen,int mode);
5755163Sshinstatic void LcpInitRestartCounter(struct fsm *);
5855163Sshinstatic void LcpLayerUp(struct fsm *);
5955163Sshinstatic void LcpLayerDown(struct fsm *);
6062607Sitojunstatic void LcpLayerStart(struct fsm *);
6155163Sshinstatic void LcpLayerFinish(struct fsm *);
6262607Sitojun
6355163Sshinextern int ModemSpeed();
6462607Sitojun
6555163Sshin#define	REJECTED(p, x)	(p->his_reject & (1<<x))
6662607Sitojun
6762607Sitojunstatic char *cftypes[] = {
6862607Sitojun  "???", "MRU", "ACCMAP", "AUTHPROTO", "QUALPROTO", "MAGICNUM",
6955163Sshin  "RESERVED", "PROTOCOMP", "ACFCOMP", "FCSALT", "SDP",
7062607Sitojun};
7162607Sitojun
7255163Sshinstruct fsm LcpFsm = {
7355163Sshin  "LCP",			/* Name of protocol */
7455163Sshin  PROTO_LCP,			/* Protocol Number */
7555163Sshin  LCP_MAXCODE,
7655163Sshin  OPEN_ACTIVE,
7762607Sitojun  ST_INITIAL,			/* State of machine */
7862607Sitojun  0, 0, 0,
7962607Sitojun  0,
8055163Sshin  { 0, 0, 0, NULL, NULL, NULL },
8155163Sshin  { 0, 0, 0, NULL, NULL, NULL },
8255163Sshin  LogLCP,
8355163Sshin
8455163Sshin  LcpLayerUp,
8555163Sshin  LcpLayerDown,
8655163Sshin  LcpLayerStart,
8755163Sshin  LcpLayerFinish,
8855163Sshin  LcpInitRestartCounter,
8955163Sshin  LcpSendConfigReq,
9055163Sshin  LcpSendTerminateReq,
9155163Sshin  LcpSendTerminateAck,
9255163Sshin  LcpDecodeConfig,
9355163Sshin};
9462607Sitojun
9555163Sshinstatic struct pppTimer LcpReportTimer;
9662607Sitojun
9755163Sshinchar *PhaseNames[] = {
9855163Sshin  "Dead", "Establish", "Authenticate", "Network", "Terminate"
9955163Sshin};
10055163Sshin
10155163Sshinvoid
10255163SshinNewPhase(new)
10355163Sshinint new;
10455163Sshin{
10555163Sshin  struct lcpstate *lcp = &LcpInfo;
10655163Sshin
10755163Sshin  phase = new;
10855163Sshin  LogPrintf(LogPHASE, "NewPhase: %s\n", PhaseNames[phase]);
10955163Sshin  switch (phase) {
11055163Sshin  case PHASE_AUTHENTICATE:
11155163Sshin    lcp->auth_ineed = lcp->want_auth;
11255163Sshin    lcp->auth_iwait = lcp->his_auth;
11355163Sshin    if (lcp->his_auth || lcp->want_auth) {
11455163Sshin      LogPrintf(LogPHASE, " his = %x, mine = %x\n", lcp->his_auth, lcp->want_auth);
11555163Sshin      if (lcp->his_auth == PROTO_PAP)
11655163Sshin	StartAuthChallenge(&AuthPapInfo);
11755163Sshin      if (lcp->want_auth == PROTO_CHAP)
11855163Sshin	StartAuthChallenge(&AuthChapInfo);
11955163Sshin    } else
12055163Sshin      NewPhase(PHASE_NETWORK);
12155163Sshin    break;
12255163Sshin  case PHASE_NETWORK:
12355163Sshin    IpcpUp();
12462607Sitojun    IpcpOpen();
12555163Sshin    CcpUp();
12655163Sshin    CcpOpen();
12755163Sshin    break;
12855163Sshin  case PHASE_DEAD:
12955163Sshin    if (mode & MODE_DIRECT)
13055163Sshin      Cleanup(EX_DEAD);
13155163Sshin    if (mode & MODE_BACKGROUND && reconnectState != RECON_TRUE)
13255163Sshin      Cleanup(EX_DEAD);
13355163Sshin    break;
13455163Sshin  }
13555163Sshin}
13655163Sshin
13755163Sshinstatic void
13855163SshinLcpReportTime()
13955163Sshin{
14055163Sshin  if (LogIsKept(LogDEBUG)) {
14155163Sshin    time_t t;
14255163Sshin
14355163Sshin    time(&t);
14455163Sshin    LogPrintf(LogDEBUG, "LcpReportTime: %s", ctime(&t));
14555163Sshin  }
14655163Sshin  StopTimer(&LcpReportTimer);
14755163Sshin  LcpReportTimer.state = TIMER_STOPPED;
14855163Sshin  StartTimer(&LcpReportTimer);
14955163Sshin  HdlcErrorCheck();
15055163Sshin}
15155163Sshin
15255163Sshinint
15355163SshinReportLcpStatus()
15455163Sshin{
15555163Sshin  struct lcpstate *lcp = &LcpInfo;
15655163Sshin  struct fsm *fp = &LcpFsm;
15755163Sshin
15855163Sshin  if (!VarTerm)
15955163Sshin    return 1;
16055163Sshin
16155163Sshin  fprintf(VarTerm, "%s [%s]\n", fp->name, StateNames[fp->state]);
16255163Sshin  fprintf(VarTerm,
16355163Sshin    " his side: MRU %ld, ACCMAP %08lx, PROTOCOMP %d, ACFCOMP %d, MAGIC %08lx,\n"
16455163Sshin    "           REJECT %04lx\n",
16555163Sshin    lcp->his_mru, lcp->his_accmap, lcp->his_protocomp, lcp->his_acfcomp,
16655163Sshin    lcp->his_magic, lcp->his_reject);
16755163Sshin  fprintf(VarTerm,
16862607Sitojun    " my  side: MRU %ld, ACCMAP %08lx, PROTOCOMP %d, ACFCOMP %d, MAGIC %08lx,\n"
16962607Sitojun    "           REJECT %04lx\n",
17055163Sshin    lcp->want_mru, lcp->want_accmap, lcp->want_protocomp, lcp->want_acfcomp,
17155163Sshin    lcp->want_magic, lcp->my_reject);
17255163Sshin  fprintf(VarTerm, "\nDefaults:   MRU = %ld, ACCMAP = %08x\t", VarMRU, VarAccmap);
17355163Sshin  fprintf(VarTerm, "Open Mode: %s\n", (VarOpenMode == OPEN_ACTIVE)? "active" : "passive");
17455163Sshin  return 0;
17555163Sshin}
17655163Sshin
17755163Sshin/*
17855163Sshin * Generate random number which will be used as magic number.
17955163Sshin */
18055163Sshinu_long
18155163SshinGenerateMagic()
18255163Sshin{
18355163Sshin  if (!randinit) {
18462607Sitojun    randinit = 1;
18555163Sshin    srandomdev();
18655163Sshin  }
18755163Sshin
18855163Sshin  return (random());
18955163Sshin}
19055163Sshin
19155163Sshinvoid
19255163SshinLcpInit()
19355163Sshin{
19455163Sshin  struct lcpstate *lcp = &LcpInfo;
19555163Sshin
19655163Sshin  FsmInit(&LcpFsm);
19755163Sshin  HdlcInit();
19855163Sshin
19955163Sshin  bzero(lcp, sizeof(struct lcpstate));
20055163Sshin  lcp->want_mru = VarMRU;
20155163Sshin  lcp->his_mru = DEF_MRU;
20255163Sshin  lcp->his_accmap = 0xffffffff;
20355163Sshin  lcp->want_accmap = VarAccmap;
20455163Sshin  lcp->want_magic = GenerateMagic();
20555163Sshin  lcp->want_auth = lcp->his_auth = 0;
20662607Sitojun  if (Enabled(ConfChap))
20762607Sitojun    lcp->want_auth = PROTO_CHAP;
20862607Sitojun  else if (Enabled(ConfPap))
20962607Sitojun    lcp->want_auth = PROTO_PAP;
21062607Sitojun  if (Enabled(ConfLqr)) lcp->want_lqrperiod = VarLqrTimeout * 100;
21155163Sshin  if (Enabled(ConfAcfcomp)) lcp->want_acfcomp = 1;
21255163Sshin  if (Enabled(ConfProtocomp)) lcp->want_protocomp = 1;
21355163Sshin  LcpFsm.maxconfig = 10;
21455163Sshin}
21555163Sshin
21655163Sshinstatic void
21755163SshinLcpInitRestartCounter(fp)
21855163Sshinstruct fsm *fp;
21962607Sitojun{
22055163Sshin  fp->FsmTimer.load = VarRetryTimeout * SECTICKS;
22155163Sshin  fp->restart = 5;
22255163Sshin}
22355163Sshin
22455163Sshinvoid
22555163SshinPutConfValue(cpp, types, type, len, val)
22655163Sshinu_char **cpp;
22755163Sshinchar **types;
22855163Sshinu_char type;
22955163Sshinint len;
23055163Sshinu_long val;
23162607Sitojun{
23255163Sshin  u_char *cp;
23355163Sshin  struct in_addr ina;
23455163Sshin
23555163Sshin  cp = *cpp;
23655163Sshin  *cp++ = type; *cp++ = len;
23755163Sshin  if (len == 6) {
23855163Sshin    if (type == TY_IPADDR) {
23955163Sshin      ina.s_addr = htonl(val);
24055163Sshin      LogPrintf(LogLCP, " %s [%d] %s\n",
24155163Sshin	types[type], len, inet_ntoa(ina));
24255163Sshin    } else {
24355163Sshin      LogPrintf(LogLCP, " %s [%d] %08x\n", types[type], len, val);
24455163Sshin    }
24555163Sshin    *cp++ = (val >> 24) & 0377;
24655163Sshin    *cp++ = (val >> 16) & 0377;
24755163Sshin  } else
24855163Sshin    LogPrintf(LogLCP, " %s [%d] %d\n", types[type], len, val);
24955163Sshin  *cp++ = (val >> 8) & 0377;
25055163Sshin  *cp++ = val & 0377;
25155163Sshin  *cpp = cp;
25255163Sshin}
25355163Sshin
25455163Sshinstatic void
25555163SshinLcpSendConfigReq(fp)
25655163Sshinstruct fsm *fp;
25755163Sshin{
25855163Sshin  u_char *cp;
25955163Sshin  struct lcpstate *lcp = &LcpInfo;
26055163Sshin  struct lqrreq *req;
26155163Sshin
26255163Sshin  LogPrintf(LogLCP, "LcpSendConfigReq\n");
26355163Sshin  cp = ReqBuff;
26455163Sshin  if (!DEV_IS_SYNC) {
26555163Sshin    if (lcp->want_acfcomp && !REJECTED(lcp, TY_ACFCOMP)) {
26655163Sshin      *cp++ = TY_ACFCOMP; *cp++ = 2;
26755163Sshin      LogPrintf(LogLCP, " %s\n", cftypes[TY_ACFCOMP]);
26855163Sshin    }
26955163Sshin    if (lcp->want_protocomp && !REJECTED(lcp, TY_PROTOCOMP)) {
27055163Sshin      *cp++ = TY_PROTOCOMP; *cp++ = 2;
27155163Sshin      LogPrintf(LogLCP, " %s\n", cftypes[TY_PROTOCOMP]);
27255163Sshin    }
27355163Sshin    if (!REJECTED(lcp, TY_ACCMAP))
27455163Sshin      PutConfValue(&cp, cftypes, TY_ACCMAP, 6, lcp->want_accmap);
27555163Sshin  }
27655163Sshin  if (!REJECTED(lcp, TY_MRU))
27755163Sshin    PutConfValue(&cp, cftypes, TY_MRU, 4, lcp->want_mru);
27855163Sshin  if (lcp->want_magic && !REJECTED(lcp, TY_MAGICNUM))
27962607Sitojun    PutConfValue(&cp, cftypes, TY_MAGICNUM, 6, lcp->want_magic);
28055163Sshin  if (lcp->want_lqrperiod && !REJECTED(lcp, TY_QUALPROTO)) {
28155163Sshin    req = (struct lqrreq *)cp;
28255163Sshin    req->type = TY_QUALPROTO; req->length = sizeof(struct lqrreq);
28355163Sshin    req->proto = htons(PROTO_LQR);
28455163Sshin    req->period = htonl(lcp->want_lqrperiod);
28555163Sshin    cp += sizeof(struct lqrreq);
28655163Sshin    LogPrintf(LogLCP, " %s (%d)\n", cftypes[TY_QUALPROTO], lcp->want_lqrperiod);
28755163Sshin  }
28855163Sshin  switch (lcp->want_auth) {
28955163Sshin  case PROTO_PAP:
29055163Sshin    PutConfValue(&cp, cftypes, TY_AUTHPROTO, 4, lcp->want_auth);
29155163Sshin    break;
29255163Sshin  case PROTO_CHAP:
29355163Sshin    PutConfValue(&cp, cftypes, TY_AUTHPROTO, 5, lcp->want_auth);
29455163Sshin    *cp++ = 5;		/* Use MD5 */
29562607Sitojun    break;
29655163Sshin  }
29762607Sitojun  FsmOutput(fp, CODE_CONFIGREQ, fp->reqid++, ReqBuff, cp - ReqBuff);
29862607Sitojun}
29955163Sshin
30055163Sshinvoid
30155163SshinLcpSendProtoRej(option, count)
30255163Sshinu_char *option;
30362607Sitojunint count;
30462607Sitojun{
30562607Sitojun  struct fsm *fp = &LcpFsm;
30655163Sshin
30755163Sshin  LogPrintf(LogLCP, "LcpSendProtoRej\n");
30855163Sshin  FsmOutput(fp, CODE_PROTOREJ, fp->reqid, option, count);
30955163Sshin}
31055163Sshin
31162607Sitojunstatic void
31255163SshinLcpSendTerminateReq(fp)
31362607Sitojunstruct fsm *fp;
31462607Sitojun{
31555163Sshin   /* Most thins are done in fsm layer. Nothing to to. */
31662607Sitojun}
31762607Sitojun
31862607Sitojunstatic void
31962607SitojunLcpSendTerminateAck(fp)
32062607Sitojunstruct fsm *fp;
32162607Sitojun{
32262607Sitojun  LogPrintf(LogLCP, "LcpSendTerminateAck.\n");
32362607Sitojun  FsmOutput(fp, CODE_TERMACK, fp->reqid++, NULL, 0);
32462607Sitojun}
32562607Sitojun
32655163Sshinstatic void
32755163SshinLcpLayerStart(fp)
32855163Sshinstruct fsm *fp;
32962607Sitojun{
33055163Sshin  LogPrintf(LogLCP, "LcpLayerStart\n");
33155163Sshin  NewPhase(PHASE_ESTABLISH);
33255163Sshin}
33355163Sshin
33455163Sshinstatic void
33555163SshinStopAllTimers()
33655163Sshin{
33755163Sshin  StopTimer(&LcpReportTimer);
33855163Sshin  StopTimer(&IpcpReportTimer);
33955163Sshin  StopIdleTimer();
34055163Sshin  StopTimer(&AuthPapInfo.authtimer);
34155163Sshin  StopTimer(&AuthChapInfo.authtimer);
34255163Sshin  StopLqrTimer();
34355163Sshin}
34455163Sshin
34555163Sshinstatic void
34655163SshinLcpLayerFinish(fp)
34755163Sshinstruct fsm *fp;
34855163Sshin{
34955163Sshin  LogPrintf(LogLCP, "LcpLayerFinish\n");
35055163Sshin  OsCloseLink(1);
35155163Sshin  NewPhase(PHASE_DEAD);
35255163Sshin  StopAllTimers();
35355163Sshin  (void)OsInterfaceDown(0);
35455163Sshin  Prompt();
35555163Sshin}
35655163Sshin
35755163Sshinstatic void
35855163SshinLcpLayerUp(fp)
35955163Sshinstruct fsm *fp;
36055163Sshin{
36155163Sshin  LogPrintf(LogLCP, "LcpLayerUp\n");
36255163Sshin  OsSetInterfaceParams(23, LcpInfo.his_mru, ModemSpeed());
36355163Sshin  SetLinkParams(&LcpInfo);
36455163Sshin
36555163Sshin  NewPhase(PHASE_AUTHENTICATE);
36662607Sitojun
36755163Sshin  StartLqm();
36855163Sshin  StopTimer(&LcpReportTimer);
36962607Sitojun  LcpReportTimer.state = TIMER_STOPPED;
37062607Sitojun  LcpReportTimer.load = 60 * SECTICKS;
37162607Sitojun  LcpReportTimer.func = LcpReportTime;
37262607Sitojun  StartTimer(&LcpReportTimer);
37362607Sitojun}
37462607Sitojun
37555163Sshinstatic void
37655163SshinLcpLayerDown(fp)
37755163Sshinstruct fsm *fp;
37855163Sshin{
37955163Sshin  LogPrintf(LogLCP, "LcpLayerDown\n");
38055163Sshin  StopAllTimers();
38155163Sshin  OsLinkdown();
38255163Sshin  NewPhase(PHASE_TERMINATE);
38355163Sshin}
38462607Sitojun
38555163Sshinvoid
38655163SshinLcpUp()
38755163Sshin{
38855163Sshin  FsmUp(&LcpFsm);
38955163Sshin}
39055163Sshin
39155163Sshinvoid
39255163SshinLcpDown()			/* Sudden death */
39355163Sshin{
39455163Sshin  NewPhase(PHASE_DEAD);
39555163Sshin  StopAllTimers();
39655163Sshin  FsmDown(&LcpFsm);
39755163Sshin}
39855163Sshin
39955163Sshinvoid
40055163SshinLcpOpen(mode)
40155163Sshinint mode;
40255163Sshin{
40355163Sshin  LcpFsm.open_mode = mode;
40455163Sshin  FsmOpen(&LcpFsm);
40555163Sshin}
40655163Sshin
40755163Sshinvoid
40855163SshinLcpClose()
40955163Sshin{
41055163Sshin  FsmClose(&LcpFsm);
41155163Sshin}
41255163Sshin
41355163Sshin/*
41455163Sshin *	XXX: Should validate option length
41555163Sshin */
41655163Sshinstatic void
41755163SshinLcpDecodeConfig(cp, plen, mode)
41855163Sshinu_char *cp;
41955163Sshinint plen;
42055163Sshinint mode;
42155163Sshin{
42255163Sshin  char *request;
42355163Sshin  int type, length, mru;
42455163Sshin  u_long *lp, magic, accmap;
42555163Sshin  u_short *sp, proto;
42655163Sshin  struct lqrreq *req;
42755163Sshin
42855163Sshin  ackp = AckBuff;
42955163Sshin  nakp = NakBuff;
43055163Sshin  rejp = RejBuff;
43155163Sshin
43255163Sshin  while (plen >= sizeof(struct fsmconfig)) {
43355163Sshin    type = *cp;
43455163Sshin    length = cp[1];
43555163Sshin    if (type <= TY_ACFCOMP)
43655163Sshin      request = cftypes[type];
43755163Sshin    else
43855163Sshin      request = "???";
43955163Sshin
44055163Sshin    switch (type) {
44155163Sshin    case TY_MRU:
44255163Sshin      sp = (u_short *)(cp + 2);
44355163Sshin      mru = htons(*sp);
44455163Sshin      LogPrintf(LogLCP, " %s %d\n", request, mru);
44555163Sshin
44655163Sshin      switch (mode) {
44755163Sshin      case MODE_REQ:
44855163Sshin	if (mru > MAX_MRU) {
44955163Sshin	  *sp = htons(MAX_MRU);
45055163Sshin	  bcopy(cp, nakp, 4); nakp += 4;
45155163Sshin	} else if (mru < MIN_MRU) {
45255163Sshin	  *sp = htons(MIN_MRU);
45355163Sshin	  bcopy(cp, nakp, 4); nakp += 4;
45455163Sshin	} else {
45562607Sitojun	  LcpInfo.his_mru = mru;
45655163Sshin	  bcopy(cp, ackp, 4); ackp += 4;
45755163Sshin	}
45855163Sshin	break;
45955163Sshin      case MODE_NAK:
46055163Sshin	if (mru >= MIN_MRU || mru <= MAX_MRU)
46155163Sshin	  LcpInfo.want_mru = mru;
46255163Sshin	break;
46355163Sshin      case MODE_REJ:
46455163Sshin	LcpInfo.his_reject |= (1 << type);
46555163Sshin	break;
46655163Sshin      }
46755163Sshin      break;
46855163Sshin    case TY_ACCMAP:
46955163Sshin      lp = (u_long *)(cp + 2);
47055163Sshin      accmap = htonl(*lp);
47155163Sshin      LogPrintf(LogLCP, " %s %08x\n", request, accmap);
47255163Sshin
47355163Sshin      switch (mode) {
47455163Sshin      case MODE_REQ:
47555163Sshin	LcpInfo.his_accmap = accmap;
47655163Sshin	bcopy(cp, ackp, 6); ackp += 6;
47755163Sshin	break;
47855163Sshin      case MODE_NAK:
47955163Sshin	LcpInfo.want_accmap = accmap;
48055163Sshin	break;
48155163Sshin      case MODE_REJ:
48255163Sshin	LcpInfo.his_reject |= (1 << type);
48355163Sshin	break;
48455163Sshin      }
48555163Sshin      break;
48655163Sshin    case TY_AUTHPROTO:
48755163Sshin      sp = (u_short *)(cp + 2);
48855163Sshin      proto = ntohs(*sp);
48955163Sshin      LogPrintf(LogLCP, " %s proto = %04x\n", request, proto);
49055163Sshin
49155163Sshin      switch (mode) {
49255163Sshin      case MODE_REQ:
49355163Sshin	switch (proto) {
49455163Sshin	case PROTO_PAP:
49555163Sshin	  if (length != 4) {
49655163Sshin	    LogPrintf(LogLCP, " %s bad length (%d)\n", request, length);
49755163Sshin	    goto reqreject;
49855163Sshin	  }
49955163Sshin	  if (Acceptable(ConfPap)) {
50055163Sshin	    LcpInfo.his_auth = proto;
50155163Sshin	    bcopy(cp, ackp, length); ackp += length;
50255163Sshin	  } else if (Acceptable(ConfChap)) {
50355163Sshin	    *nakp++ = *cp; *nakp++ = 5;
50455163Sshin	    *nakp++ = (unsigned char)(PROTO_CHAP >> 8);
50555163Sshin	    *nakp++ = (unsigned char)PROTO_CHAP;
50655163Sshin	    *nakp++ = 5;
50755163Sshin	  } else
50855163Sshin	    goto reqreject;
50955163Sshin	  break;
51055163Sshin	case PROTO_CHAP:
51155163Sshin	  if (length < 5) {
51255163Sshin	    LogPrintf(LogLCP, " %s bad length (%d)\n", request, length);
51355163Sshin	    goto reqreject;
51455163Sshin	  }
51555163Sshin	  if (Acceptable(ConfChap) && cp[4] == 5) {
51655163Sshin	    LcpInfo.his_auth = proto;
51755163Sshin	    bcopy(cp, ackp, length); ackp += length;
51855163Sshin	  } else if (Acceptable(ConfPap)) {
51962607Sitojun	    *nakp++ = *cp; *nakp++ = 4;
52055163Sshin	    *nakp++ = (unsigned char)(PROTO_PAP >> 8);
52162607Sitojun	    *nakp++ = (unsigned char)PROTO_PAP;
52255163Sshin	  } else
52355163Sshin	    goto reqreject;
52455163Sshin	  break;
52555163Sshin	default:
52655163Sshin 	    LogPrintf(LogLCP, " %s not implemented, NAK.\n", request);
52755163Sshin            bcopy(cp, nakp, length);
52855163Sshin            nakp += length;
52955163Sshin            break;
53055163Sshin	}
53155163Sshin	break;
53255163Sshin      case MODE_NAK:
53355163Sshin	break;
53455163Sshin      case MODE_REJ:
53555163Sshin	LcpInfo.his_reject |= (1 << type);
53655163Sshin	break;
53755163Sshin      }
53855163Sshin      break;
53955163Sshin    case TY_QUALPROTO:
54055163Sshin      req = (struct lqrreq *)cp;
54155163Sshin      LogPrintf(LogLCP, " %s proto: %x, interval: %dms\n",
54255163Sshin		request, ntohs(req->proto), ntohl(req->period)*10);
54355163Sshin      switch (mode) {
54455163Sshin      case MODE_REQ:
54555163Sshin	if (ntohs(req->proto) != PROTO_LQR || !Acceptable(ConfLqr))
54655163Sshin	  goto reqreject;
54755163Sshin	else {
54855163Sshin	  LcpInfo.his_lqrperiod = ntohl(req->period);
54955163Sshin	  if (LcpInfo.his_lqrperiod < 500)
55055163Sshin	    LcpInfo.his_lqrperiod = 500;
55155163Sshin	  req->period = htonl(LcpInfo.his_lqrperiod);
55255163Sshin	  bcopy(cp, ackp, length); ackp += length;
55355163Sshin	}
55462607Sitojun	break;
55555163Sshin      case MODE_NAK:
55662607Sitojun	break;
55762607Sitojun      case MODE_REJ:
55862607Sitojun	LcpInfo.his_reject |= (1 << type);
55962607Sitojun	break;
56062607Sitojun      }
56162607Sitojun      break;
56262607Sitojun    case TY_MAGICNUM:
56355163Sshin      lp = (u_long *)(cp + 2);
56462607Sitojun      magic = ntohl(*lp);
56562607Sitojun      LogPrintf(LogLCP, " %s %08x\n", request, magic);
56655163Sshin
56755163Sshin      switch (mode) {
56855163Sshin      case MODE_REQ:
56955163Sshin	if (LcpInfo.want_magic) {
57055163Sshin	  /* Validate magic number */
57155163Sshin	  if (magic == LcpInfo.want_magic) {
57255163Sshin	    LogPrintf(LogLCP, "Magic is same (%08x)\n", magic);
57355163Sshin	    LcpInfo.want_magic = GenerateMagic();
57455163Sshin	    bcopy(cp, nakp, 6);
57555163Sshin            nakp += 6;
57655163Sshin          } else {
57755163Sshin	    LcpInfo.his_magic = magic;
57855163Sshin	    bcopy(cp, ackp, length); ackp += length;
57955163Sshin          }
58055163Sshin	} else {
58155163Sshin	  LcpInfo.my_reject |= (1 << type);
58255163Sshin	  goto reqreject;
58355163Sshin	}
58455163Sshin	break;
58555163Sshin      case MODE_NAK:
58655163Sshin	LogPrintf(LogLCP, " %s magic %08x has NAKed\n", request, magic);
58755163Sshin	LcpInfo.want_magic = GenerateMagic();
58855163Sshin	break;
58955163Sshin      case MODE_REJ:
59055163Sshin	LogPrintf(LogLCP, " %s magic has REJected\n", request);
59155163Sshin	LcpInfo.want_magic = 0;
59262607Sitojun	LcpInfo.his_reject |= (1 << type);
59362607Sitojun	break;
59455163Sshin      }
59555163Sshin      break;
59655163Sshin    case TY_PROTOCOMP:
59755163Sshin      LogPrintf(LogLCP, " %s\n", request);
59855163Sshin
59955163Sshin      switch (mode) {
60055163Sshin      case MODE_REQ:
60155163Sshin        if (Acceptable(ConfProtocomp)) {
60255163Sshin	  LcpInfo.his_protocomp = 1;
60355163Sshin	  bcopy(cp, ackp, 2); ackp += 2;
60455163Sshin        } else {
60555163Sshin#ifdef OLDMST
60655163Sshin	  /*
60755163Sshin	   * MorningStar before v1.3 needs NAK
60855163Sshin	   */
60955163Sshin	  bcopy(cp, nakp, 2); nakp += 2;
61055163Sshin#else
61155163Sshin	  bcopy(cp, rejp, 2); rejp += 2;
61255163Sshin	  LcpInfo.my_reject |= (1 << type);
61355163Sshin#endif
61455163Sshin        }
61555163Sshin	break;
61655163Sshin      case MODE_NAK:
61755163Sshin      case MODE_REJ:
61855163Sshin	LcpInfo.want_protocomp = 0;
61955163Sshin	LcpInfo.his_reject |= (1 << type);
62055163Sshin	break;
62162607Sitojun      }
62255163Sshin      break;
62355163Sshin    case TY_ACFCOMP:
62455163Sshin      LogPrintf(LogLCP, " %s\n", request);
62555163Sshin      switch (mode) {
62655163Sshin      case MODE_REQ:
62755163Sshin        if (Acceptable(ConfAcfcomp)) {
62855163Sshin	  LcpInfo.his_acfcomp = 1;
62955163Sshin	  bcopy(cp, ackp, 2);
63055163Sshin	  ackp += 2;
63155163Sshin        } else {
63255163Sshin#ifdef OLDMST
63355163Sshin	  /*
63455163Sshin	   * MorningStar before v1.3 needs NAK
63555163Sshin	   */
63655163Sshin	  bcopy(cp, nakp, 2);
63755163Sshin	  nakp += 2;
63855163Sshin#else
63955163Sshin	  bcopy(cp, rejp, 2);
64055163Sshin	  rejp += 2;
64155163Sshin	  LcpInfo.my_reject |= (1 << type);
64255163Sshin#endif
64355163Sshin	}
64455163Sshin	break;
64555163Sshin      case MODE_NAK:
64655163Sshin      case MODE_REJ:
64755163Sshin	LcpInfo.want_acfcomp = 0;
64855163Sshin	LcpInfo.his_reject |= (1 << type);
64955163Sshin	break;
65055163Sshin      }
65155163Sshin      break;
65255163Sshin    case TY_SDP:
65355163Sshin      LogPrintf(LogLCP, " %s\n", request);
65455163Sshin      switch (mode) {
65555163Sshin      case MODE_REQ:
65655163Sshin      case MODE_NAK:
65755163Sshin      case MODE_REJ:
65855163Sshin	break;
65955163Sshin      }
66055163Sshin      break;
66155163Sshin    default:
66255163Sshin      LogPrintf(LogLCP, " ???[%02x]\n", type);
66355163Sshin      if (mode == MODE_REQ) {
66455163Sshinreqreject:
66555163Sshin        bcopy(cp, rejp, length);
66655163Sshin        rejp += length;
66755163Sshin        LcpInfo.my_reject |= (1 << type);
66855163Sshin      }
66962607Sitojun      break;
67062607Sitojun    }
67155163Sshin    /* to avoid inf. loop */
67255163Sshin    if (length == 0) {
67355163Sshin      LogPrintf(LogLCP, "LCP size zero\n");
67455163Sshin      break;
67562607Sitojun    }
67655163Sshin
67755163Sshin    plen -= length;
67855163Sshin    cp += length;
67955163Sshin  }
68055163Sshin}
68155163Sshin
68255163Sshinvoid
68355163SshinLcpInput(struct mbuf *bp)
68455163Sshin{
68555163Sshin  FsmInput(&LcpFsm, bp);
68655163Sshin}
68755163Sshin