fsm.c revision 6059
16059Samurai/*
26059Samurai *		PPP Finite State Machine for LCP/IPCP
36059Samurai *
46059Samurai *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
56059Samurai *
66059Samurai *   Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
76059Samurai *
86059Samurai * Redistribution and use in source and binary forms are permitted
96059Samurai * provided that the above copyright notice and this paragraph are
106059Samurai * duplicated in all such forms and that any documentation,
116059Samurai * advertising materials, and other materials related to such
126059Samurai * distribution and use acknowledge that the software was developed
136059Samurai * by the Internet Initiative Japan, Inc.  The name of the
146059Samurai * IIJ may not be used to endorse or promote products derived
156059Samurai * from this software without specific prior written permission.
166059Samurai * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
176059Samurai * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
186059Samurai * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
196059Samurai *
206059Samurai * $Id:$
216059Samurai *
226059Samurai *  TODO:
236059Samurai *		o Refer loglevel for log output
246059Samurai *		o Better option log display
256059Samurai */
266059Samurai#include "fsm.h"
276059Samurai#include "hdlc.h"
286059Samurai#include "lqr.h"
296059Samurai#include "lcpproto.h"
306059Samurai#include "lcp.h"
316059Samurai
326059Samuraivoid FsmSendConfigReq(struct fsm *fp);
336059Samuraivoid FsmSendTerminateReq(struct fsm *fp);
346059Samuraivoid FsmInitRestartCounter(struct fsm *fp);
356059Samuraivoid FsmTimeout(struct fsm *fp);
366059Samurai
376059Samuraichar *StateNames[] = {
386059Samurai  "Initial", "Starting", "Closed", "Stopped", "Closing", "Stopping",
396059Samurai  "Req-Sent", "Ack-Rcvd", "Ack-Sent", "Opend",
406059Samurai};
416059Samurai
426059Samuraivoid
436059SamuraiFsmInit(fp)
446059Samuraistruct fsm *fp;
456059Samurai{
466059Samurai#ifdef DEBUG
476059Samurai  logprintf("FsmInit\n");
486059Samurai#endif
496059Samurai  fp->state = ST_INITIAL;
506059Samurai  fp->reqid = 1;
516059Samurai  fp->restart = 1;
526059Samurai  fp->maxconfig = 3;
536059Samurai}
546059Samurai
556059Samuraivoid
566059SamuraiNewState(fp, new)
576059Samuraistruct fsm *fp;
586059Samuraiint new;
596059Samurai{
606059Samurai  LogPrintf(LOG_LCP, "%s: state change %s --> %s\n",
616059Samurai	  fp->name, StateNames[fp->state], StateNames[new]);
626059Samurai  fp->state = new;
636059Samurai  if ((new >= ST_INITIAL && new <= ST_STOPPED) || (new == ST_OPENED))
646059Samurai    StopTimer(&fp->FsmTimer);
656059Samurai}
666059Samurai
676059Samuraivoid
686059SamuraiFsmOutput(fp, code, id, ptr, count)
696059Samuraistruct fsm *fp;
706059Samuraiu_int code, id;
716059Samuraiu_char *ptr;
726059Samuraiint count;
736059Samurai{
746059Samurai  int plen;
756059Samurai  struct fsmheader lh;
766059Samurai  struct mbuf *bp;
776059Samurai
786059Samurai  plen =  sizeof(struct fsmheader) + count;
796059Samurai  lh.code = code;
806059Samurai  lh.id = id;
816059Samurai  lh.length = htons(plen);
826059Samurai  bp = mballoc(plen, MB_FSM);
836059Samurai  bcopy(&lh, MBUF_CTOP(bp), sizeof(struct fsmheader));
846059Samurai  if (count)
856059Samurai    bcopy(ptr, MBUF_CTOP(bp) + sizeof(struct fsmheader), count);
866059Samurai#ifdef DEBUG
876059Samurai  DumpBp(bp);
886059Samurai#endif
896059Samurai  HdlcOutput(PRI_NORMAL, fp->proto, bp);
906059Samurai}
916059Samurai
926059Samuraivoid
936059SamuraiFsmOpen(fp)
946059Samuraistruct fsm *fp;
956059Samurai{
966059Samurai  switch (fp->state) {
976059Samurai  case ST_INITIAL:
986059Samurai    (fp->LayerStart)(fp);
996059Samurai    NewState(fp, ST_STARTING);
1006059Samurai    break;
1016059Samurai  case ST_STARTING:
1026059Samurai    break;
1036059Samurai  case ST_CLOSED:
1046059Samurai    if (fp->open_mode == OPEN_PASSIVE) {
1056059Samurai      NewState(fp, ST_STOPPED);
1066059Samurai    } else {
1076059Samurai      FsmInitRestartCounter(fp);
1086059Samurai      FsmSendConfigReq(fp);
1096059Samurai      NewState(fp, ST_REQSENT);
1106059Samurai    }
1116059Samurai    break;
1126059Samurai  case ST_STOPPED:	/* XXX: restart option */
1136059Samurai  case ST_REQSENT:
1146059Samurai  case ST_ACKRCVD:
1156059Samurai  case ST_ACKSENT:
1166059Samurai  case ST_OPENED:	/* XXX: restart option */
1176059Samurai    break;
1186059Samurai  case ST_CLOSING:	/* XXX: restart option */
1196059Samurai  case ST_STOPPING:	/* XXX: restart option */
1206059Samurai    NewState(fp, ST_STOPPING);
1216059Samurai    break;
1226059Samurai  }
1236059Samurai}
1246059Samurai
1256059Samuraivoid
1266059SamuraiFsmUp(fp)
1276059Samuraistruct fsm *fp;
1286059Samurai{
1296059Samurai  switch (fp->state) {
1306059Samurai  case ST_INITIAL:
1316059Samurai    NewState(fp, ST_CLOSED);
1326059Samurai    break;
1336059Samurai  case ST_STARTING:
1346059Samurai    FsmInitRestartCounter(fp);
1356059Samurai    FsmSendConfigReq(fp);
1366059Samurai    NewState(fp, ST_REQSENT);
1376059Samurai    break;
1386059Samurai  default:
1396059Samurai    LogPrintf(LOG_LCP, "%s: Oops, Up at %s\n",
1406059Samurai	    fp->name, StateNames[fp->state]);
1416059Samurai    break;
1426059Samurai  }
1436059Samurai}
1446059Samurai
1456059Samuraivoid
1466059SamuraiFsmDown(fp)
1476059Samuraistruct fsm *fp;
1486059Samurai{
1496059Samurai  switch (fp->state) {
1506059Samurai  case ST_CLOSED:
1516059Samurai  case ST_CLOSING:
1526059Samurai    NewState(fp, ST_INITIAL);
1536059Samurai    break;
1546059Samurai  case ST_STOPPED:
1556059Samurai    (fp->LayerStart)(fp);
1566059Samurai    /* Fall into.. */
1576059Samurai  case ST_STOPPING:
1586059Samurai  case ST_REQSENT:
1596059Samurai  case ST_ACKRCVD:
1606059Samurai  case ST_ACKSENT:
1616059Samurai    NewState(fp, ST_STARTING);
1626059Samurai    break;
1636059Samurai  case ST_OPENED:
1646059Samurai    (fp->LayerDown)(fp);
1656059Samurai    NewState(fp, ST_STARTING);
1666059Samurai    break;
1676059Samurai  }
1686059Samurai}
1696059Samurai
1706059Samuraivoid
1716059SamuraiFsmClose(fp)
1726059Samuraistruct fsm *fp;
1736059Samurai{
1746059Samurai  switch (fp->state) {
1756059Samurai  case ST_STARTING:
1766059Samurai    NewState(fp, ST_INITIAL);
1776059Samurai    break;
1786059Samurai  case ST_STOPPED:
1796059Samurai    NewState(fp, ST_CLOSED);
1806059Samurai    break;
1816059Samurai  case ST_STOPPING:
1826059Samurai    NewState(fp, ST_CLOSING);
1836059Samurai    break;
1846059Samurai  case ST_OPENED:
1856059Samurai    (fp->LayerDown)(fp);
1866059Samurai    /* Fall down */
1876059Samurai  case ST_REQSENT:
1886059Samurai  case ST_ACKRCVD:
1896059Samurai  case ST_ACKSENT:
1906059Samurai    FsmInitRestartCounter(fp);
1916059Samurai    FsmSendTerminateReq(fp);
1926059Samurai    NewState(fp, ST_CLOSING);
1936059Samurai    break;
1946059Samurai  }
1956059Samurai}
1966059Samurai
1976059Samurai/*
1986059Samurai *	Send functions
1996059Samurai */
2006059Samuraivoid
2016059SamuraiFsmSendConfigReq(fp)
2026059Samuraistruct fsm *fp;
2036059Samurai{
2046059Samurai  if (--fp->maxconfig > 0) {
2056059Samurai    (fp->SendConfigReq)(fp);
2066059Samurai    StartTimer(&fp->FsmTimer);	/* Start restart timer */
2076059Samurai    fp->restart--;		/* Decrement restart counter */
2086059Samurai  } else {
2096059Samurai    FsmClose(fp);
2106059Samurai  }
2116059Samurai}
2126059Samurai
2136059Samuraivoid
2146059SamuraiFsmSendTerminateReq(fp)
2156059Samuraistruct fsm *fp;
2166059Samurai{
2176059Samurai  LogPrintf(LOG_LCP, "%s: SendTerminateReq.\n", fp->name);
2186059Samurai  FsmOutput(fp, CODE_TERMREQ, fp->reqid++, NULL, 0);
2196059Samurai  (fp->SendTerminateReq)(fp);
2206059Samurai  StartTimer(&fp->FsmTimer);	/* Start restart timer */
2216059Samurai  fp->restart--;		/* Decrement restart counter */
2226059Samurai}
2236059Samurai
2246059Samuraistatic void
2256059SamuraiFsmSendConfigAck(fp, lhp, option, count)
2266059Samuraistruct fsm *fp;
2276059Samuraistruct fsmheader *lhp;
2286059Samuraiu_char *option;
2296059Samuraiint count;
2306059Samurai{
2316059Samurai  LogPrintf(LOG_LCP, "%s:  SendConfigAck(%s)\n", fp->name, StateNames[fp->state]);
2326059Samurai  FsmOutput(fp, CODE_CONFIGACK, lhp->id, option, count);
2336059Samurai}
2346059Samurai
2356059Samuraistatic void
2366059SamuraiFsmSendConfigRej(fp, lhp, option, count)
2376059Samuraistruct fsm *fp;
2386059Samuraistruct fsmheader *lhp;
2396059Samuraiu_char *option;
2406059Samuraiint count;
2416059Samurai{
2426059Samurai  LogPrintf(LOG_LCP, "%s:  SendConfigRej(%s)\n", fp->name, StateNames[fp->state]);
2436059Samurai  FsmOutput(fp, CODE_CONFIGREJ, lhp->id, option, count);
2446059Samurai}
2456059Samurai
2466059Samuraistatic void
2476059SamuraiFsmSendConfigNak(fp, lhp, option, count)
2486059Samuraistruct fsm *fp;
2496059Samuraistruct fsmheader *lhp;
2506059Samuraiu_char *option;
2516059Samuraiint count;
2526059Samurai{
2536059Samurai  LogPrintf(LOG_LCP, "%s:  SendConfigNak(%s)\n",
2546059Samurai	    fp->name, StateNames[fp->state]);
2556059Samurai  FsmOutput(fp, CODE_CONFIGNAK, lhp->id, option, count);
2566059Samurai}
2576059Samurai
2586059Samurai/*
2596059Samurai *	Timeout actions
2606059Samurai */
2616059Samuraivoid
2626059SamuraiFsmTimeout(fp)
2636059Samuraistruct fsm *fp;
2646059Samurai{
2656059Samurai  if (fp->restart) {
2666059Samurai    switch (fp->state) {
2676059Samurai    case ST_CLOSING:
2686059Samurai    case ST_STOPPING:
2696059Samurai      FsmSendTerminateReq(fp);
2706059Samurai      break;
2716059Samurai    case ST_REQSENT:
2726059Samurai    case ST_ACKSENT:
2736059Samurai      FsmSendConfigReq(fp);
2746059Samurai      break;
2756059Samurai    case ST_ACKRCVD:
2766059Samurai      FsmSendConfigReq(fp);
2776059Samurai      NewState(fp, ST_REQSENT);
2786059Samurai      break;
2796059Samurai    }
2806059Samurai    StartTimer(&fp->FsmTimer);
2816059Samurai  } else {
2826059Samurai    switch (fp->state) {
2836059Samurai    case ST_CLOSING:
2846059Samurai      NewState(fp, ST_CLOSED);
2856059Samurai      (fp->LayerFinish)(fp);
2866059Samurai      break;
2876059Samurai    case ST_STOPPING:
2886059Samurai      NewState(fp, ST_STOPPED);
2896059Samurai      (fp->LayerFinish)(fp);
2906059Samurai      break;
2916059Samurai    case ST_REQSENT:		/* XXX: 3p */
2926059Samurai    case ST_ACKSENT:
2936059Samurai    case ST_ACKRCVD:
2946059Samurai      NewState(fp, ST_STOPPED);
2956059Samurai      (fp->LayerFinish)(fp);
2966059Samurai      break;
2976059Samurai    }
2986059Samurai  }
2996059Samurai}
3006059Samurai
3016059Samuraivoid
3026059SamuraiFsmInitRestartCounter(fp)
3036059Samuraistruct fsm *fp;
3046059Samurai{
3056059Samurai  StopTimer(&fp->FsmTimer);
3066059Samurai  fp->FsmTimer.state = TIMER_STOPPED;
3076059Samurai  fp->FsmTimer.func = FsmTimeout;
3086059Samurai  fp->FsmTimer.arg = (void *)fp;
3096059Samurai  (fp->InitRestartCounter)(fp);
3106059Samurai}
3116059Samurai
3126059Samurai/*
3136059Samurai *   Actions when receive packets
3146059Samurai */
3156059Samuraivoid
3166059SamuraiFsmRecvConfigReq(fp, lhp, bp)			/* RCR */
3176059Samuraistruct fsm *fp;
3186059Samuraistruct fsmheader *lhp;
3196059Samuraistruct mbuf *bp;
3206059Samurai{
3216059Samurai  int plen;
3226059Samurai  int ackaction = 0;
3236059Samurai
3246059Samurai  plen = plength(bp);
3256059Samurai  if (plen < sizeof(struct fsmconfig)) {
3266059Samurailogprintf("** plen = %d\n", plen);
3276059Samurai    pfree(bp);
3286059Samurai    return;
3296059Samurai  }
3306059Samurai
3316059Samurai  /*
3326059Samurai   *  Check and process easy case
3336059Samurai   */
3346059Samurai  switch (fp->state) {
3356059Samurai  case ST_INITIAL:
3366059Samurai  case ST_STARTING:
3376059Samurai    LogPrintf(LOG_LCP, "%s: Oops, RCR in %s.\n",
3386059Samurai	    fp->name, StateNames[fp->state]);
3396059Samurai    pfree(bp);
3406059Samurai    return;
3416059Samurai  case ST_CLOSED:
3426059Samurai    (fp->SendTerminateAck)(fp);
3436059Samurai    pfree(bp);
3446059Samurai    return;
3456059Samurai  case ST_CLOSING:
3466059Samurai  case ST_STOPPING:
3476059Samurailogprintf("## state = %d\n", fp->state);
3486059Samurai    pfree(bp);
3496059Samurai    return;
3506059Samurai  }
3516059Samurai
3526059Samurai  (fp->DecodeConfig)(bp, MODE_REQ);
3536059Samurai
3546059Samurai  if (nakp == NakBuff && rejp == RejBuff)
3556059Samurai    ackaction = 1;
3566059Samurai
3576059Samurai  switch (fp->state) {
3586059Samurai  case ST_OPENED:
3596059Samurai    (fp->LayerDown)(fp);
3606059Samurai    FsmSendConfigReq(fp);
3616059Samurai    break;
3626059Samurai  case ST_STOPPED:
3636059Samurai    FsmInitRestartCounter(fp);
3646059Samurai    FsmSendConfigReq(fp);
3656059Samurai    break;
3666059Samurai  }
3676059Samurai
3686059Samurai  if (rejp != RejBuff)
3696059Samurai    FsmSendConfigRej(fp, lhp, RejBuff, rejp - RejBuff);
3706059Samurai  if (nakp != NakBuff)
3716059Samurai    FsmSendConfigNak(fp, lhp, NakBuff, nakp - NakBuff);
3726059Samurai  if (ackaction)
3736059Samurai    FsmSendConfigAck(fp, lhp, AckBuff, ackp - AckBuff);
3746059Samurai
3756059Samurai  switch (fp->state) {
3766059Samurai  case ST_STOPPED:
3776059Samurai  case ST_OPENED:
3786059Samurai    if (ackaction)
3796059Samurai      NewState(fp, ST_ACKSENT);
3806059Samurai    else
3816059Samurai      NewState(fp, ST_REQSENT);
3826059Samurai    break;
3836059Samurai  case ST_REQSENT:
3846059Samurai    if (ackaction)
3856059Samurai      NewState(fp, ST_ACKSENT);
3866059Samurai    break;
3876059Samurai  case ST_ACKRCVD:
3886059Samurai    if (ackaction) {
3896059Samurai      NewState(fp, ST_OPENED);
3906059Samurai      (fp->LayerUp)(fp);
3916059Samurai    }
3926059Samurai    break;
3936059Samurai  case ST_ACKSENT:
3946059Samurai    if (!ackaction)
3956059Samurai      NewState(fp, ST_REQSENT);
3966059Samurai    break;
3976059Samurai  }
3986059Samurai  pfree(bp);
3996059Samurai}
4006059Samurai
4016059Samuraivoid
4026059SamuraiFsmRecvConfigAck(fp, lhp, bp)			/* RCA */
4036059Samuraistruct fsm *fp;
4046059Samuraistruct fsmheader *lhp;
4056059Samuraistruct mbuf *bp;
4066059Samurai{
4076059Samurai  switch (fp->state) {
4086059Samurai  case ST_CLOSED:
4096059Samurai  case ST_STOPPED:
4106059Samurai    (fp->SendTerminateAck)(fp);
4116059Samurai    break;
4126059Samurai  case ST_CLOSING:
4136059Samurai  case ST_STOPPING:
4146059Samurai    break;
4156059Samurai  case ST_REQSENT:
4166059Samurai    FsmInitRestartCounter(fp);
4176059Samurai    NewState(fp, ST_ACKRCVD);
4186059Samurai    break;
4196059Samurai  case ST_ACKRCVD:
4206059Samurai    FsmSendConfigReq(fp);
4216059Samurai    NewState(fp, ST_REQSENT);
4226059Samurai    break;
4236059Samurai  case ST_ACKSENT:
4246059Samurai    FsmInitRestartCounter(fp);
4256059Samurai    NewState(fp, ST_OPENED);
4266059Samurai    (fp->LayerUp)(fp);
4276059Samurai    break;
4286059Samurai  case ST_OPENED:
4296059Samurai    (fp->LayerDown)(fp);
4306059Samurai    FsmSendConfigReq(fp);
4316059Samurai    NewState(fp, ST_REQSENT);
4326059Samurai    break;
4336059Samurai  }
4346059Samurai  pfree(bp);
4356059Samurai}
4366059Samurai
4376059Samuraivoid
4386059SamuraiFsmRecvConfigNak(fp, lhp, bp)			/* RCN */
4396059Samuraistruct fsm *fp;
4406059Samuraistruct fsmheader *lhp;
4416059Samuraistruct mbuf *bp;
4426059Samurai{
4436059Samurai  int plen;
4446059Samurai
4456059Samurai  plen = plength(bp);
4466059Samurai  if (plen < sizeof(struct fsmconfig)) {
4476059Samurai    pfree(bp);
4486059Samurai    return;
4496059Samurai  }
4506059Samurai
4516059Samurai  /*
4526059Samurai   *  Check and process easy case
4536059Samurai   */
4546059Samurai  switch (fp->state) {
4556059Samurai  case ST_INITIAL:
4566059Samurai  case ST_STARTING:
4576059Samurai    LogPrintf(LOG_LCP, "%s: Oops, RCN in %s.\n",
4586059Samurai	    fp->name, StateNames[fp->state]);
4596059Samurai    pfree(bp);
4606059Samurai    return;
4616059Samurai  case ST_CLOSED:
4626059Samurai  case ST_STOPPED:
4636059Samurai    (fp->SendTerminateAck)(fp);
4646059Samurai    pfree(bp);
4656059Samurai    return;
4666059Samurai  case ST_CLOSING:
4676059Samurai  case ST_STOPPING:
4686059Samurai    pfree(bp);
4696059Samurai    return;
4706059Samurai  }
4716059Samurai
4726059Samurai  (fp->DecodeConfig)(bp, MODE_NAK);
4736059Samurai
4746059Samurai  switch (fp->state) {
4756059Samurai  case ST_REQSENT:
4766059Samurai  case ST_ACKSENT:
4776059Samurai    FsmInitRestartCounter(fp);
4786059Samurai    FsmSendConfigReq(fp);
4796059Samurai    break;
4806059Samurai  case ST_OPENED:
4816059Samurai    (fp->LayerDown)(fp);
4826059Samurai    /* Fall down */
4836059Samurai  case ST_ACKRCVD:
4846059Samurai    FsmSendConfigReq(fp);
4856059Samurai    NewState(fp, ST_REQSENT);
4866059Samurai    break;
4876059Samurai  }
4886059Samurai
4896059Samurai  pfree(bp);
4906059Samurai}
4916059Samurai
4926059Samuraivoid
4936059SamuraiFsmRecvTermReq(fp, lhp, bp)				/* RTR */
4946059Samuraistruct fsm *fp;
4956059Samuraistruct fsmheader *lhp;
4966059Samuraistruct mbuf *bp;
4976059Samurai{
4986059Samurai  switch (fp->state) {
4996059Samurai  case ST_INITIAL:
5006059Samurai  case ST_STARTING:
5016059Samurai    LogPrintf(LOG_LCP, "%s: Oops, RTR in %s\n", fp->name,
5026059Samurai	    StateNames[fp->state]);
5036059Samurai    break;
5046059Samurai  case ST_CLOSED:
5056059Samurai  case ST_STOPPED:
5066059Samurai  case ST_CLOSING:
5076059Samurai  case ST_STOPPING:
5086059Samurai  case ST_REQSENT:
5096059Samurai    (fp->SendTerminateAck)(fp);
5106059Samurai    break;
5116059Samurai  case ST_ACKRCVD:
5126059Samurai  case ST_ACKSENT:
5136059Samurai    (fp->SendTerminateAck)(fp);
5146059Samurai    NewState(fp, ST_REQSENT);
5156059Samurai    break;
5166059Samurai  case ST_OPENED:
5176059Samurai    (fp->LayerDown)(fp);
5186059Samurai    /* Zero Restart counter */
5196059Samurai    (fp->SendTerminateAck)(fp);
5206059Samurai    NewState(fp, ST_STOPPING);
5216059Samurai    break;
5226059Samurai  }
5236059Samurai  pfree(bp);
5246059Samurai}
5256059Samurai
5266059Samuraivoid
5276059SamuraiFsmRecvTermAck(fp, lhp, bp)			/* RTA */
5286059Samuraistruct fsm *fp;
5296059Samuraistruct fsmheader *lhp;
5306059Samuraistruct mbuf *bp;
5316059Samurai{
5326059Samurai  switch (fp->state) {
5336059Samurai  case ST_CLOSING:
5346059Samurai    NewState(fp, ST_CLOSED);
5356059Samurai    (fp->LayerFinish)(fp);
5366059Samurai    break;
5376059Samurai  case ST_STOPPING:
5386059Samurai    NewState(fp, ST_STOPPED);
5396059Samurai    (fp->LayerFinish)(fp);
5406059Samurai    break;
5416059Samurai  case ST_ACKRCVD:
5426059Samurai    NewState(fp, ST_REQSENT);
5436059Samurai    break;
5446059Samurai  case ST_OPENED:
5456059Samurai    (fp->LayerDown)(fp);
5466059Samurai    FsmSendConfigReq(fp);
5476059Samurai    NewState(fp, ST_REQSENT);
5486059Samurai    break;
5496059Samurai  }
5506059Samurai  pfree(bp);
5516059Samurai}
5526059Samurai
5536059Samuraivoid
5546059SamuraiFsmRecvConfigRej(fp, lhp, bp)			/* RCJ */
5556059Samuraistruct fsm *fp;
5566059Samuraistruct fsmheader *lhp;
5576059Samuraistruct mbuf *bp;
5586059Samurai{
5596059Samurai  int plen;
5606059Samurai
5616059Samurai  plen = plength(bp);
5626059Samurai  if (plen < sizeof(struct fsmconfig)) {
5636059Samurai    pfree(bp);
5646059Samurai    return;
5656059Samurai  }
5666059Samurai  LogPrintf(LOG_LCP, "%s: RecvConfigRej.\n", fp->name);
5676059Samurai
5686059Samurai  /*
5696059Samurai   *  Check and process easy case
5706059Samurai   */
5716059Samurai  switch (fp->state) {
5726059Samurai  case ST_INITIAL:
5736059Samurai  case ST_STARTING:
5746059Samurai    LogPrintf(LOG_LCP, "%s: Oops, RCJ in %s.\n",
5756059Samurai	    fp->name, StateNames[fp->state]);
5766059Samurai    pfree(bp);
5776059Samurai    return;
5786059Samurai  case ST_CLOSED:
5796059Samurai  case ST_STOPPED:
5806059Samurai    (fp->SendTerminateAck)(fp);
5816059Samurai    pfree(bp);
5826059Samurai    return;
5836059Samurai  case ST_CLOSING:
5846059Samurai  case ST_STOPPING:
5856059Samurai    pfree(bp);
5866059Samurai    return;
5876059Samurai  }
5886059Samurai
5896059Samurai  (fp->DecodeConfig)(bp, MODE_REJ);
5906059Samurai
5916059Samurai  switch (fp->state) {
5926059Samurai  case ST_REQSENT:
5936059Samurai  case ST_ACKSENT:
5946059Samurai    FsmInitRestartCounter(fp);
5956059Samurai    FsmSendConfigReq(fp);
5966059Samurai    break;
5976059Samurai  case ST_OPENED:
5986059Samurai    (fp->LayerDown)(fp);
5996059Samurai    /* Fall down */
6006059Samurai  case ST_ACKRCVD:
6016059Samurai    FsmSendConfigReq(fp);
6026059Samurai    NewState(fp, ST_REQSENT);
6036059Samurai    break;
6046059Samurai  }
6056059Samurai  pfree(bp);
6066059Samurai}
6076059Samurai
6086059Samuraivoid
6096059SamuraiFsmRecvCodeRej(fp, lhp, bp)
6106059Samuraistruct fsm *fp;
6116059Samuraistruct fsmheader *lhp;
6126059Samuraistruct mbuf *bp;
6136059Samurai{
6146059Samurai  LogPrintf(LOG_LCP, "%s: RecvCodeRej\n", fp->name);
6156059Samurai  pfree(bp);
6166059Samurai}
6176059Samurai
6186059Samuraivoid
6196059SamuraiFsmRecvProtoRej(fp, lhp, bp)
6206059Samuraistruct fsm *fp;
6216059Samuraistruct fsmheader *lhp;
6226059Samuraistruct mbuf *bp;
6236059Samurai{
6246059Samurai  u_short *sp, proto;
6256059Samurai
6266059Samurai  sp = (u_short *)MBUF_CTOP(bp);
6276059Samurai  proto = ntohs(*sp);
6286059Samurai  LogPrintf(LOG_LCP, "-- Protocol (%04x) was rejected.\n", proto);
6296059Samurai
6306059Samurai  switch (proto) {
6316059Samurai  case PROTO_LQR:
6326059Samurai    StopLqr(LQM_LQR);
6336059Samurai    break;
6346059Samurai  case PROTO_CCP:
6356059Samurai    fp = &CcpFsm;
6366059Samurai    (fp->LayerFinish)(fp);
6376059Samurai    switch (fp->state) {
6386059Samurai    case ST_CLOSED:
6396059Samurai    case ST_CLOSING:
6406059Samurai      NewState(fp, ST_CLOSED);
6416059Samurai    default:
6426059Samurai      NewState(fp, ST_STOPPED);
6436059Samurai      break;
6446059Samurai    }
6456059Samurai    break;
6466059Samurai  }
6476059Samurai  pfree(bp);
6486059Samurai}
6496059Samurai
6506059Samuraivoid
6516059SamuraiFsmRecvEchoReq(fp, lhp, bp)
6526059Samuraistruct fsm *fp;
6536059Samuraistruct fsmheader *lhp;
6546059Samuraistruct mbuf *bp;
6556059Samurai{
6566059Samurai  u_char *cp;
6576059Samurai  u_long *lp, magic;
6586059Samurai
6596059Samurai  cp = MBUF_CTOP(bp);
6606059Samurai  lp = (u_long *)cp;
6616059Samurai  magic = ntohl(*lp);
6626059Samurai  if (magic != LcpInfo.his_magic) {
6636059Samurai    logprintf("RecvEchoReq: his magic is bad!!\n");
6646059Samurai    /* XXX: We should send terminate request */
6656059Samurai  }
6666059Samurai
6676059Samurai  if (fp->state == ST_OPENED) {
6686059Samurai    *lp = htonl(LcpInfo.want_magic);	/* Insert local magic number */
6696059Samurai    LogPrintf(LOG_LCP, "%s:  SendEchoRep(%s)\n", fp->name, StateNames[fp->state]);
6706059Samurai    FsmOutput(fp, CODE_ECHOREP, lhp->id, cp, plength(bp));
6716059Samurai  }
6726059Samurai  pfree(bp);
6736059Samurai}
6746059Samurai
6756059Samuraivoid
6766059SamuraiFsmRecvEchoRep(fp, lhp, bp)
6776059Samuraistruct fsm *fp;
6786059Samuraistruct fsmheader *lhp;
6796059Samuraistruct mbuf *bp;
6806059Samurai{
6816059Samurai  u_long *lp, magic;
6826059Samurai
6836059Samurai  lp = (u_long *)MBUF_CTOP(bp);
6846059Samurai  magic = ntohl(*lp);
6856059Samurai  if (magic != 0 && magic != LcpInfo.his_magic) {
6866059Samurai    logprintf("RecvEchoRep: his magic is wrong! expect: %x got: %x\n",
6876059Samurai	LcpInfo.his_magic, magic);
6886059Samurai    /*
6896059Samurai     *  XXX: We should send terminate request. But poor implementation
6906059Samurai     *       may die as a result.
6916059Samurai     */
6926059Samurai  }
6936059Samurai  RecvEchoLqr(bp);
6946059Samurai  pfree(bp);
6956059Samurai}
6966059Samurai
6976059Samuraivoid
6986059SamuraiFsmRecvDiscReq(fp, lhp, bp)
6996059Samuraistruct fsm *fp;
7006059Samuraistruct fsmheader *lhp;
7016059Samuraistruct mbuf *bp;
7026059Samurai{
7036059Samurai  LogPrintf(LOG_LCP, "%s: RecvDiscReq\n", fp->name);
7046059Samurai  pfree(bp);
7056059Samurai}
7066059Samurai
7076059Samuraivoid
7086059SamuraiFsmRecvIdent(fp, lhp, bp)
7096059Samuraistruct fsm *fp;
7106059Samuraistruct fsmheader *lhp;
7116059Samuraistruct mbuf *bp;
7126059Samurai{
7136059Samurai  LogPrintf(LOG_LCP, "%s: RecvIdent\n", fp->name);
7146059Samurai  pfree(bp);
7156059Samurai}
7166059Samurai
7176059Samuraivoid
7186059SamuraiFsmRecvTimeRemain(fp, lhp, bp)
7196059Samuraistruct fsm *fp;
7206059Samuraistruct fsmheader *lhp;
7216059Samuraistruct mbuf *bp;
7226059Samurai{
7236059Samurai  LogPrintf(LOG_LCP, "%s: RecvTimeRemain\n", fp->name);
7246059Samurai  pfree(bp);
7256059Samurai}
7266059Samurai
7276059Samuraivoid
7286059SamuraiFsmRecvResetReq(fp, lhp, bp)
7296059Samuraistruct fsm *fp;
7306059Samuraistruct fsmheader *lhp;
7316059Samuraistruct mbuf *bp;
7326059Samurai{
7336059Samurai  LogPrintf(LOG_LCP, "%s: RecvResetReq\n", fp->name);
7346059Samurai  CcpRecvResetReq(fp);
7356059Samurai  LogPrintf(LOG_LCP, "%s: SendResetAck\n", fp->name);
7366059Samurai  FsmOutput(fp, CODE_RESETACK, fp->reqid, NULL, 0);
7376059Samurai  pfree(bp);
7386059Samurai}
7396059Samurai
7406059Samuraivoid
7416059SamuraiFsmRecvResetAck(fp, lhp, bp)
7426059Samuraistruct fsm *fp;
7436059Samuraistruct fsmheader *lhp;
7446059Samuraistruct mbuf *bp;
7456059Samurai{
7466059Samurai  LogPrintf(LOG_LCP, "%s: RecvResetAck\n", fp->name);
7476059Samurai  fp->reqid++;
7486059Samurai  pfree(bp);
7496059Samurai}
7506059Samurai
7516059Samuraistruct fsmcodedesc FsmCodes[] = {
7526059Samurai { FsmRecvConfigReq,  "Configure Request", },
7536059Samurai { FsmRecvConfigAck,  "Configure Ack", },
7546059Samurai { FsmRecvConfigNak,  "Configure Nak", },
7556059Samurai { FsmRecvConfigRej,  "Configure Reject", },
7566059Samurai { FsmRecvTermReq,    "Terminate Request", },
7576059Samurai { FsmRecvTermAck,    "Terminate Ack", },
7586059Samurai { FsmRecvCodeRej,    "Code Reject", },
7596059Samurai { FsmRecvProtoRej,   "Protocol Reject", },
7606059Samurai { FsmRecvEchoReq,    "Echo Request", },
7616059Samurai { FsmRecvEchoRep,    "Echo Reply", },
7626059Samurai { FsmRecvDiscReq,    "Discard Request", },
7636059Samurai { FsmRecvIdent,      "Ident", },
7646059Samurai { FsmRecvTimeRemain, "Time Remain", },
7656059Samurai { FsmRecvResetReq,   "Reset Request", },
7666059Samurai { FsmRecvResetAck,   "Reset Ack", },
7676059Samurai};
7686059Samurai
7696059Samuraivoid
7706059SamuraiFsmInput(fp, bp)
7716059Samuraistruct fsm *fp;
7726059Samuraistruct mbuf *bp;
7736059Samurai{
7746059Samurai  int len;
7756059Samurai  struct fsmheader *lhp;
7766059Samurai  struct fsmcodedesc *codep;
7776059Samurai
7786059Samurai  len = plength(bp);
7796059Samurai  if (len < sizeof(struct fsmheader)) {
7806059Samurai    pfree(bp);
7816059Samurai    return;
7826059Samurai  }
7836059Samurai  lhp = (struct fsmheader *)MBUF_CTOP(bp);
7846059Samurai  if (lhp->code == 0 || lhp->code > fp->max_code) {
7856059Samurai    pfree(bp);		/* XXX: Should send code reject */
7866059Samurai    return;
7876059Samurai  }
7886059Samurai
7896059Samurai  bp->offset += sizeof(struct fsmheader);
7906059Samurai  bp->cnt -= sizeof(struct fsmheader);
7916059Samurai
7926059Samurai  codep = FsmCodes + lhp->code - 1;
7936059Samurai  LogPrintf(LOG_LCP, "%s: Received %s (%d) state = %s (%d)\n",
7946059Samurai    fp->name, codep->name, lhp->code, StateNames[fp->state], fp->state);
7956059Samurai#ifdef DEBUG
7966059Samurai  LogMemory();
7976059Samurai#endif
7986059Samurai  (codep->action)(fp, lhp, bp);
7996059Samurai#ifdef DEBUG
8006059Samurai  LogMemory();
8016059Samurai#endif
8026059Samurai}
803