fsm.c revision 37210
169800Stomsoft/*
269800Stomsoft *		PPP Finite State Machine for LCP/IPCP
369800Stomsoft *
469800Stomsoft *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
5114067Sschweikh *
669800Stomsoft *   Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
769800Stomsoft *
8114067Sschweikh * Redistribution and use in source and binary forms are permitted
969800Stomsoft * provided that the above copyright notice and this paragraph are
1069800Stomsoft * duplicated in all such forms and that any documentation,
1169800Stomsoft * advertising materials, and other materials related to such
1269800Stomsoft * distribution and use acknowledge that the software was developed
1369800Stomsoft * by the Internet Initiative Japan, Inc.  The name of the
1469800Stomsoft * IIJ may not be used to endorse or promote products derived
1569800Stomsoft * from this software without specific prior written permission.
1669800Stomsoft * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1769800Stomsoft * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1869800Stomsoft * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1969800Stomsoft *
2069800Stomsoft * $Id: fsm.c,v 1.33 1998/06/25 22:33:20 brian Exp $
2169800Stomsoft *
2269800Stomsoft *  TODO:
2369800Stomsoft */
2469800Stomsoft
25114067Sschweikh#include <sys/types.h>
2669800Stomsoft#include <netinet/in.h>
2769800Stomsoft#include <netinet/in_systm.h>
2869800Stomsoft#include <netinet/ip.h>
2969800Stomsoft#include <sys/un.h>
3069800Stomsoft
3169800Stomsoft#include <string.h>
3269800Stomsoft#include <termios.h>
3369800Stomsoft
3469800Stomsoft#include "mbuf.h"
3569800Stomsoft#include "log.h"
3669800Stomsoft#include "defs.h"
3769800Stomsoft#include "timer.h"
3869926Stomsoft#include "fsm.h"
3969800Stomsoft#include "iplist.h"
4069800Stomsoft#include "lqr.h"
4169800Stomsoft#include "hdlc.h"
4269800Stomsoft#include "throughput.h"
4369800Stomsoft#include "slcompress.h"
4469800Stomsoft#include "ipcp.h"
4569800Stomsoft#include "filter.h"
4669800Stomsoft#include "descriptor.h"
4769800Stomsoft#include "lcp.h"
4869800Stomsoft#include "ccp.h"
4969800Stomsoft#include "link.h"
5069800Stomsoft#include "mp.h"
5169926Stomsoft#include "bundle.h"
5269800Stomsoft#include "async.h"
5369800Stomsoft#include "physical.h"
5469800Stomsoft#include "lcpproto.h"
5569800Stomsoft
5669800Stomsoftstatic void FsmSendConfigReq(struct fsm *);
5769800Stomsoftstatic void FsmSendTerminateReq(struct fsm *);
5869800Stomsoftstatic void FsmInitRestartCounter(struct fsm *);
5969800Stomsoft
6069800Stomsofttypedef void (recvfn)(struct fsm *, struct fsmheader *, struct mbuf *);
6169800Stomsoftstatic recvfn FsmRecvConfigReq, FsmRecvConfigAck, FsmRecvConfigNak,
6269800Stomsoft              FsmRecvConfigRej, FsmRecvTermReq, FsmRecvTermAck,
6369800Stomsoft              FsmRecvCodeRej, FsmRecvProtoRej, FsmRecvEchoReq,
6469800Stomsoft              FsmRecvEchoRep, FsmRecvDiscReq, FsmRecvIdent,
65103949Smike              FsmRecvTimeRemain, FsmRecvResetReq, FsmRecvResetAck;
6669800Stomsoft
6769800Stomsoftstatic const struct fsmcodedesc {
6869800Stomsoft  recvfn *recv;
6969800Stomsoft  unsigned check_reqid : 1;
7069800Stomsoft  unsigned inc_reqid : 1;
7169800Stomsoft  const char *name;
7269800Stomsoft} FsmCodes[] = {
7369800Stomsoft  { FsmRecvConfigReq, 0, 0, "ConfigReq"    },
7469800Stomsoft  { FsmRecvConfigAck, 1, 1, "ConfigAck"    },
7569800Stomsoft  { FsmRecvConfigNak, 1, 1, "ConfigNak"    },
7669800Stomsoft  { FsmRecvConfigRej, 1, 1, "ConfigRej"    },
7769800Stomsoft  { FsmRecvTermReq,   0, 0, "TerminateReq" },
7869800Stomsoft  { FsmRecvTermAck,   1, 1, "TerminateAck" },
7969800Stomsoft  { FsmRecvCodeRej,   0, 0, "CodeRej"      },
8069800Stomsoft  { FsmRecvProtoRej,  0, 0, "ProtocolRej"  },
8198542Smckusick  { FsmRecvEchoReq,   0, 0, "EchoRequest"  },
8269800Stomsoft  { FsmRecvEchoRep,   0, 0, "EchoReply"    },
8369800Stomsoft  { FsmRecvDiscReq,   0, 0, "DiscardReq"   },
8469800Stomsoft  { FsmRecvIdent,     0, 0, "Ident"        },
8569800Stomsoft  { FsmRecvTimeRemain,0, 0, "TimeRemain"   },
8698542Smckusick  { FsmRecvResetReq,  0, 0, "ResetReqt"    },
8798542Smckusick  { FsmRecvResetAck,  0, 1, "ResetAck"     }
8898542Smckusick};
8998542Smckusick
9098542Smckusickstatic const char *
9198542SmckusickCode2Nam(u_int code)
9269800Stomsoft{
9369800Stomsoft  if (code == 0 || code > sizeof FsmCodes / sizeof FsmCodes[0])
9469800Stomsoft    return "Unknown";
9569800Stomsoft  return FsmCodes[code-1].name;
9669800Stomsoft}
9769800Stomsoft
9869800Stomsoftconst char *
9998542SmckusickState2Nam(u_int state)
10069800Stomsoft{
10198542Smckusick  static const char *StateNames[] = {
10269800Stomsoft    "Initial", "Starting", "Closed", "Stopped", "Closing", "Stopping",
10398542Smckusick    "Req-Sent", "Ack-Rcvd", "Ack-Sent", "Opened",
10498542Smckusick  };
10598542Smckusick
10669800Stomsoft  if (state >= sizeof StateNames / sizeof StateNames[0])
10798542Smckusick    return "unknown";
10898542Smckusick  return StateNames[state];
10998542Smckusick}
11098542Smckusick
11198542Smckusickstatic void
11298542SmckusickStoppedTimeout(void *v)
11369800Stomsoft{
11469800Stomsoft  struct fsm *fp = (struct fsm *)v;
115114067Sschweikh
11669800Stomsoft  log_Printf(fp->LogLevel, "%s: Stopped timer expired\n", fp->link->name);
11769800Stomsoft  if (fp->OpenTimer.state == TIMER_RUNNING) {
11869800Stomsoft    log_Printf(LogWARN, "%s: %s: aborting open delay due to stopped timer\n",
11969800Stomsoft              fp->link->name, fp->name);
12098542Smckusick    timer_Stop(&fp->OpenTimer);
12198542Smckusick  }
12269800Stomsoft  if (fp->state == ST_STOPPED)
12369800Stomsoft    fsm2initial(fp);
12477885Stomsoft}
12569800Stomsoft
12669800Stomsoftvoid
12769800Stomsoftfsm_Init(struct fsm *fp, const char *name, u_short proto, int mincode,
12869800Stomsoft         int maxcode, int maxcfg, int LogLevel, struct bundle *bundle,
12977885Stomsoft         struct link *l, const struct fsm_parent *parent,
13098542Smckusick         struct fsm_callbacks *fn, const char *timer_names[3])
13198542Smckusick{
13298542Smckusick  fp->name = name;
13369800Stomsoft  fp->proto = proto;
13469926Stomsoft  fp->min_code = mincode;
13569800Stomsoft  fp->max_code = maxcode;
13669800Stomsoft  fp->state = fp->min_code > CODE_TERMACK ? ST_OPENED : ST_INITIAL;
13769800Stomsoft  fp->reqid = 1;
13877885Stomsoft  fp->restart = 1;
13977885Stomsoft  fp->maxconfig = maxcfg;
14077885Stomsoft  memset(&fp->FsmTimer, '\0', sizeof fp->FsmTimer);
14169800Stomsoft  memset(&fp->OpenTimer, '\0', sizeof fp->OpenTimer);
14277885Stomsoft  memset(&fp->StoppedTimer, '\0', sizeof fp->StoppedTimer);
14398542Smckusick  fp->LogLevel = LogLevel;
14498542Smckusick  fp->link = l;
14598542Smckusick  fp->bundle = bundle;
14698542Smckusick  fp->parent = parent;
14769800Stomsoft  fp->fn = fn;
14877885Stomsoft  fp->FsmTimer.name = timer_names[0];
14998542Smckusick  fp->OpenTimer.name = timer_names[1];
15098542Smckusick  fp->StoppedTimer.name = timer_names[2];
15169800Stomsoft}
15269800Stomsoft
15369800Stomsoftstatic void
154114067SschweikhNewState(struct fsm * fp, int new)
155114067Sschweikh{
156114067Sschweikh  log_Printf(fp->LogLevel, "%s: State change %s --> %s\n",
15769800Stomsoft	    fp->link->name, State2Nam(fp->state), State2Nam(new));
158114067Sschweikh  if (fp->state == ST_STOPPED && fp->StoppedTimer.state == TIMER_RUNNING)
159114067Sschweikh    timer_Stop(&fp->StoppedTimer);
160114067Sschweikh  fp->state = new;
16169800Stomsoft  if ((new >= ST_INITIAL && new <= ST_STOPPED) || (new == ST_OPENED)) {
16269800Stomsoft    timer_Stop(&fp->FsmTimer);
16369800Stomsoft    if (new == ST_STOPPED && fp->StoppedTimer.load) {
16469800Stomsoft      timer_Stop(&fp->StoppedTimer);
16577885Stomsoft      fp->StoppedTimer.func = StoppedTimeout;
16669800Stomsoft      fp->StoppedTimer.arg = (void *) fp;
16769800Stomsoft      timer_Start(&fp->StoppedTimer);
16877885Stomsoft    }
16977885Stomsoft  }
17069800Stomsoft}
17169800Stomsoft
17269800Stomsoftvoid
17369800Stomsoftfsm_Output(struct fsm *fp, u_int code, u_int id, u_char *ptr, int count)
17469800Stomsoft{
17569800Stomsoft  int plen;
17669800Stomsoft  struct fsmheader lh;
17769800Stomsoft  struct mbuf *bp;
17869800Stomsoft
17969800Stomsoft  if (log_IsKept(fp->LogLevel)) {
18069800Stomsoft    log_Printf(fp->LogLevel, "%s: Send%s(%d) state = %s\n",
18169800Stomsoft              fp->link->name, Code2Nam(code), id, State2Nam(fp->state));
18269800Stomsoft    switch (code) {
18369800Stomsoft      case CODE_CONFIGREQ:
18469800Stomsoft      case CODE_CONFIGACK:
18569800Stomsoft      case CODE_CONFIGREJ:
18669800Stomsoft      case CODE_CONFIGNAK:
18769800Stomsoft        (*fp->fn->DecodeConfig)(fp, ptr, count, MODE_NOP, NULL);
18869800Stomsoft        if (count < sizeof(struct fsmconfig))
18969800Stomsoft          log_Printf(fp->LogLevel, "  [EMPTY]\n");
19069800Stomsoft        break;
19169800Stomsoft    }
19277885Stomsoft  }
19369926Stomsoft
19469926Stomsoft  plen = sizeof(struct fsmheader) + count;
19569926Stomsoft  lh.code = code;
19669800Stomsoft  lh.id = id;
19769800Stomsoft  lh.length = htons(plen);
19877885Stomsoft  bp = mbuf_Alloc(plen, MB_FSM);
19977885Stomsoft  memcpy(MBUF_CTOP(bp), &lh, sizeof(struct fsmheader));
20069800Stomsoft  if (count)
20169800Stomsoft    memcpy(MBUF_CTOP(bp) + sizeof(struct fsmheader), ptr, count);
20269800Stomsoft  log_DumpBp(LogDEBUG, "fsm_Output", bp);
20369800Stomsoft  hdlc_Output(fp->link, PRI_LINK, fp->proto, bp);
20469800Stomsoft}
20569800Stomsoft
20669800Stomsoftstatic void
20769800StomsoftFsmOpenNow(void *v)
20869800Stomsoft{
20969800Stomsoft  struct fsm *fp = (struct fsm *)v;
21077885Stomsoft
21177885Stomsoft  timer_Stop(&fp->OpenTimer);
21269926Stomsoft  if (fp->state <= ST_STOPPED) {
21369926Stomsoft    if (fp->state != ST_STARTING) {
21469926Stomsoft      /*
21569800Stomsoft       * In practice, we're only here in ST_STOPPED (when delaying the
21669800Stomsoft       * first config request) or ST_CLOSED (when openmode == 0).
21769800Stomsoft       *
21869800Stomsoft       * The ST_STOPPED bit is breaking the RFC already :-(
21969800Stomsoft       *
22069800Stomsoft       * According to the RFC (1661) state transition table, a TLS isn't
22169800Stomsoft       * required for an Open event when state == Closed, but the RFC
22269800Stomsoft       * must be wrong as TLS hasn't yet been called (since the last TLF)
22369800Stomsoft       * ie, Initial gets an `Up' event, Closing gets a RTA etc.
22469800Stomsoft       */
22569800Stomsoft      (*fp->fn->LayerStart)(fp);
226102231Strhodes      (*fp->parent->LayerStart)(fp->parent->object, fp);
22769800Stomsoft    }
22898542Smckusick    FsmInitRestartCounter(fp);
22998542Smckusick    FsmSendConfigReq(fp);
23069800Stomsoft    NewState(fp, ST_REQSENT);
23198542Smckusick  }
23298542Smckusick}
23398542Smckusick
23498542Smckusickvoid
23598542Smckusickfsm_Open(struct fsm * fp)
23698542Smckusick{
23798542Smckusick  switch (fp->state) {
23869800Stomsoft  case ST_INITIAL:
23969800Stomsoft    NewState(fp, ST_STARTING);
24069800Stomsoft    (*fp->fn->LayerStart)(fp);
24169800Stomsoft    (*fp->parent->LayerStart)(fp->parent->object, fp);
24269800Stomsoft    break;
24369800Stomsoft  case ST_CLOSED:
24469800Stomsoft    if (fp->open_mode == OPEN_PASSIVE) {
24569800Stomsoft      NewState(fp, ST_STOPPED);		/* XXX: This is a hack ! */
24669800Stomsoft    } else if (fp->open_mode > 0) {
24769800Stomsoft      if (fp->open_mode > 1)
24869800Stomsoft        log_Printf(LogPHASE, "%s: Entering STOPPED state for %d seconds\n",
24969800Stomsoft                  fp->link->name, fp->open_mode);
25069800Stomsoft      NewState(fp, ST_STOPPED);		/* XXX: This is a not-so-bad hack ! */
25169800Stomsoft      timer_Stop(&fp->OpenTimer);
25277885Stomsoft      fp->OpenTimer.load = fp->open_mode * SECTICKS;
25377885Stomsoft      fp->OpenTimer.func = FsmOpenNow;
25469800Stomsoft      fp->OpenTimer.arg = (void *)fp;
25569800Stomsoft      timer_Start(&fp->OpenTimer);
25669800Stomsoft    } else
25769800Stomsoft      FsmOpenNow(fp);
25869800Stomsoft    break;
25969800Stomsoft  case ST_STOPPED:		/* XXX: restart option */
26069800Stomsoft  case ST_REQSENT:
26169800Stomsoft  case ST_ACKRCVD:
26269800Stomsoft  case ST_ACKSENT:
26369800Stomsoft  case ST_OPENED:		/* XXX: restart option */
26469800Stomsoft    break;
26569800Stomsoft  case ST_CLOSING:		/* XXX: restart option */
26669800Stomsoft  case ST_STOPPING:		/* XXX: restart option */
26769800Stomsoft    NewState(fp, ST_STOPPING);
26869800Stomsoft    break;
26969800Stomsoft  }
27069800Stomsoft}
27169800Stomsoft
27269800Stomsoftvoid
27369800Stomsoftfsm_Up(struct fsm * fp)
27469800Stomsoft{
27569800Stomsoft  switch (fp->state) {
27677885Stomsoft  case ST_INITIAL:
27777885Stomsoft    log_Printf(fp->LogLevel, "FSM: Using \"%s\" as a transport\n",
27869800Stomsoft              fp->link->name);
27969800Stomsoft    NewState(fp, ST_CLOSED);
28069800Stomsoft    break;
28169800Stomsoft  case ST_STARTING:
28269800Stomsoft    FsmInitRestartCounter(fp);
28369800Stomsoft    FsmSendConfigReq(fp);
28469800Stomsoft    NewState(fp, ST_REQSENT);
28569800Stomsoft    break;
28669800Stomsoft  default:
28769800Stomsoft    log_Printf(fp->LogLevel, "%s: Oops, Up at %s\n",
28869800Stomsoft              fp->link->name, State2Nam(fp->state));
28977885Stomsoft    break;
29077885Stomsoft  }
29169926Stomsoft}
29269926Stomsoft
29369926Stomsoftvoid
29469800Stomsoftfsm_Down(struct fsm *fp)
29569800Stomsoft{
29669800Stomsoft  switch (fp->state) {
29769800Stomsoft  case ST_CLOSED:
29869800Stomsoft    NewState(fp, ST_INITIAL);
29969800Stomsoft    break;
30069800Stomsoft  case ST_CLOSING:
30169800Stomsoft    (*fp->fn->LayerFinish)(fp);
30298542Smckusick    NewState(fp, ST_INITIAL);
30369800Stomsoft    (*fp->parent->LayerFinish)(fp->parent->object, fp);
30469926Stomsoft    break;
30569926Stomsoft  case ST_STOPPED:
30669800Stomsoft    NewState(fp, ST_STARTING);
30769800Stomsoft    (*fp->fn->LayerStart)(fp);
30869800Stomsoft    (*fp->parent->LayerStart)(fp->parent->object, fp);
30969800Stomsoft    break;
31069800Stomsoft  case ST_STOPPING:
31169800Stomsoft  case ST_REQSENT:
31269800Stomsoft  case ST_ACKRCVD:
31369800Stomsoft  case ST_ACKSENT:
31469800Stomsoft    NewState(fp, ST_STARTING);
31569800Stomsoft    break;
31669800Stomsoft  case ST_OPENED:
31769800Stomsoft    (*fp->fn->LayerDown)(fp);
31869800Stomsoft    NewState(fp, ST_STARTING);
31969800Stomsoft    (*fp->parent->LayerDown)(fp->parent->object, fp);
320114067Sschweikh    break;
32169800Stomsoft  }
32269800Stomsoft}
32369800Stomsoft
32469800Stomsoftvoid
32569800Stomsoftfsm_Close(struct fsm *fp)
32669800Stomsoft{
32769800Stomsoft  switch (fp->state) {
32869800Stomsoft  case ST_STARTING:
32969800Stomsoft    (*fp->fn->LayerFinish)(fp);
33069800Stomsoft    NewState(fp, ST_INITIAL);
33169800Stomsoft    (*fp->parent->LayerFinish)(fp->parent->object, fp);
332114067Sschweikh    break;
33369800Stomsoft  case ST_STOPPED:
33469800Stomsoft    NewState(fp, ST_CLOSED);
335114067Sschweikh    break;
33669800Stomsoft  case ST_STOPPING:
33769800Stomsoft    NewState(fp, ST_CLOSING);
33869800Stomsoft    break;
33969800Stomsoft  case ST_OPENED:
34069800Stomsoft    (*fp->fn->LayerDown)(fp);
34169800Stomsoft    FsmInitRestartCounter(fp);
34269800Stomsoft    FsmSendTerminateReq(fp);
34369800Stomsoft    NewState(fp, ST_CLOSING);
34498542Smckusick    (*fp->parent->LayerDown)(fp->parent->object, fp);
34569800Stomsoft    break;
34669800Stomsoft  case ST_REQSENT:
34769926Stomsoft  case ST_ACKRCVD:
34869926Stomsoft  case ST_ACKSENT:
34969800Stomsoft    FsmInitRestartCounter(fp);
35069800Stomsoft    FsmSendTerminateReq(fp);
35169800Stomsoft    NewState(fp, ST_CLOSING);
35269800Stomsoft    break;
35369800Stomsoft  }
35469800Stomsoft}
35569800Stomsoft
356114067Sschweikh/*
357114067Sschweikh *	Send functions
358114067Sschweikh */
35969800Stomsoftstatic void
36069800StomsoftFsmSendConfigReq(struct fsm * fp)
36169800Stomsoft{
36277885Stomsoft  if (--fp->maxconfig > 0) {
36369800Stomsoft    (*fp->fn->SendConfigReq)(fp);
36469800Stomsoft    timer_Start(&fp->FsmTimer);	/* Start restart timer */
36598542Smckusick    fp->restart--;		/* Decrement restart counter */
36698542Smckusick  } else {
36798542Smckusick    fsm_Close(fp);
36898542Smckusick  }
36998542Smckusick}
37092806Sobrien
37169800Stomsoftstatic void
37298542SmckusickFsmSendTerminateReq(struct fsm *fp)
37398542Smckusick{
37498542Smckusick  fsm_Output(fp, CODE_TERMREQ, fp->reqid, NULL, 0);
37569800Stomsoft  (*fp->fn->SentTerminateReq)(fp);
37669800Stomsoft  timer_Start(&fp->FsmTimer);	/* Start restart timer */
37798542Smckusick  fp->restart--;		/* Decrement restart counter */
37898542Smckusick}
37969800Stomsoft
38069800Stomsoft/*
38169800Stomsoft *	Timeout actions
38298542Smckusick */
38369800Stomsoftstatic void
38469800StomsoftFsmTimeout(void *v)
38569800Stomsoft{
38698542Smckusick  struct fsm *fp = (struct fsm *)v;
38769800Stomsoft
38898542Smckusick  if (fp->restart) {
38998542Smckusick    switch (fp->state) {
39069800Stomsoft    case ST_CLOSING:
39169800Stomsoft    case ST_STOPPING:
39269800Stomsoft      FsmSendTerminateReq(fp);
39369800Stomsoft      break;
39498542Smckusick    case ST_REQSENT:
39569800Stomsoft    case ST_ACKSENT:
39698542Smckusick      FsmSendConfigReq(fp);
39769800Stomsoft      break;
39898542Smckusick    case ST_ACKRCVD:
39998542Smckusick      FsmSendConfigReq(fp);
40098542Smckusick      NewState(fp, ST_REQSENT);
40198542Smckusick      break;
40298542Smckusick    }
40398542Smckusick    timer_Start(&fp->FsmTimer);
40498542Smckusick  } else {
40598542Smckusick    switch (fp->state) {
40698542Smckusick    case ST_CLOSING:
40798542Smckusick      (*fp->fn->LayerFinish)(fp);
40898542Smckusick      NewState(fp, ST_CLOSED);
40998542Smckusick      (*fp->parent->LayerFinish)(fp->parent->object, fp);
41098542Smckusick      break;
41198542Smckusick    case ST_STOPPING:
41298542Smckusick      (*fp->fn->LayerFinish)(fp);
41369800Stomsoft      NewState(fp, ST_STOPPED);
414103949Smike      (*fp->parent->LayerFinish)(fp->parent->object, fp);
415103949Smike      break;
41698542Smckusick    case ST_REQSENT:		/* XXX: 3p */
41769800Stomsoft    case ST_ACKSENT:
41898542Smckusick    case ST_ACKRCVD:
41998542Smckusick      (*fp->fn->LayerFinish)(fp);
42069800Stomsoft      NewState(fp, ST_STOPPED);
42169800Stomsoft      (*fp->parent->LayerFinish)(fp->parent->object, fp);
42298542Smckusick      break;
423103949Smike    }
42469800Stomsoft  }
42598542Smckusick}
42669800Stomsoft
42798542Smckusickstatic void
428102231StrhodesFsmInitRestartCounter(struct fsm * fp)
42969800Stomsoft{
43069926Stomsoft  timer_Stop(&fp->FsmTimer);
43169800Stomsoft  fp->FsmTimer.func = FsmTimeout;
43269800Stomsoft  fp->FsmTimer.arg = (void *) fp;
43369800Stomsoft  (*fp->fn->InitRestartCounter)(fp);
43498542Smckusick}
43569800Stomsoft
43669800Stomsoft/*
43769800Stomsoft *   Actions when receive packets
43898542Smckusick */
43969800Stomsoftstatic void
44098542SmckusickFsmRecvConfigReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp)
44198542Smckusick/* RCR */
44269800Stomsoft{
44398542Smckusick  struct fsm_decode dec;
44498542Smckusick  int plen, flen;
44598542Smckusick  int ackaction = 0;
44698542Smckusick
44798542Smckusick  plen = mbuf_Length(bp);
44898542Smckusick  flen = ntohs(lhp->length) - sizeof *lhp;
44998542Smckusick  if (plen < flen) {
45098542Smckusick    log_Printf(LogWARN, "%s: FsmRecvConfigReq: plen (%d) < flen (%d)\n",
45169800Stomsoft	      fp->link->name, plen, flen);
45269800Stomsoft    mbuf_Free(bp);
45398542Smckusick    return;
45469800Stomsoft  }
45598542Smckusick
45698542Smckusick  /*
45798542Smckusick   * Check and process easy case
45898542Smckusick   */
45998542Smckusick  switch (fp->state) {
46098542Smckusick  case ST_INITIAL:
46198542Smckusick  case ST_STARTING:
46298542Smckusick    log_Printf(fp->LogLevel, "%s: Oops, RCR in %s.\n",
46398542Smckusick              fp->link->name, State2Nam(fp->state));
46498542Smckusick    mbuf_Free(bp);
46598542Smckusick    return;
46669800Stomsoft  case ST_CLOSED:
46798542Smckusick    (*fp->fn->SendTerminateAck)(fp, lhp->id);
46869800Stomsoft    mbuf_Free(bp);
46969800Stomsoft    return;
47069800Stomsoft  case ST_CLOSING:
47169800Stomsoft    log_Printf(fp->LogLevel, "%s: Error: Got ConfigReq while state = %s\n",
47269800Stomsoft              fp->link->name, State2Nam(fp->state));
47369800Stomsoft  case ST_STOPPING:
47469800Stomsoft    mbuf_Free(bp);
47569800Stomsoft    return;
47669800Stomsoft  }
47798542Smckusick
47898542Smckusick  dec.ackend = dec.ack;
47969800Stomsoft  dec.nakend = dec.nak;
48069800Stomsoft  dec.rejend = dec.rej;
48198542Smckusick  (*fp->fn->DecodeConfig)(fp, MBUF_CTOP(bp), flen, MODE_REQ, &dec);
48269800Stomsoft  if (flen < sizeof(struct fsmconfig))
48369800Stomsoft    log_Printf(fp->LogLevel, "  [EMPTY]\n");
48469800Stomsoft
48598542Smckusick  if (dec.nakend == dec.nak && dec.rejend == dec.rej)
48698542Smckusick    ackaction = 1;
48798542Smckusick
48869800Stomsoft  switch (fp->state) {
48969800Stomsoft  case ST_OPENED:
49069800Stomsoft    (*fp->fn->LayerDown)(fp);
49169800Stomsoft    FsmSendConfigReq(fp);
49269800Stomsoft    (*fp->parent->LayerDown)(fp->parent->object, fp);
49398542Smckusick    break;
49498542Smckusick  case ST_STOPPED:
49598542Smckusick    FsmInitRestartCounter(fp);
49698542Smckusick    FsmSendConfigReq(fp);
49798542Smckusick    break;
49869800Stomsoft  }
49969800Stomsoft
50098542Smckusick  if (dec.rejend != dec.rej)
50169800Stomsoft    fsm_Output(fp, CODE_CONFIGREJ, lhp->id, dec.rej, dec.rejend - dec.rej);
50298542Smckusick  if (dec.nakend != dec.nak)
50398542Smckusick    fsm_Output(fp, CODE_CONFIGNAK, lhp->id, dec.nak, dec.nakend - dec.nak);
50469800Stomsoft  if (ackaction)
50569800Stomsoft    fsm_Output(fp, CODE_CONFIGACK, lhp->id, dec.ack, dec.ackend - dec.ack);
50669800Stomsoft
50769800Stomsoft  switch (fp->state) {
508103949Smike  case ST_OPENED:
50969800Stomsoft  case ST_STOPPED:
51098542Smckusick    if (ackaction)
51169800Stomsoft      NewState(fp, ST_ACKSENT);
51269800Stomsoft    else
51369800Stomsoft      NewState(fp, ST_REQSENT);
51469800Stomsoft    break;
51569800Stomsoft  case ST_REQSENT:
51698542Smckusick    if (ackaction)
51769800Stomsoft      NewState(fp, ST_ACKSENT);
51869800Stomsoft    break;
51969800Stomsoft  case ST_ACKRCVD:
52069800Stomsoft    if (ackaction) {
52169800Stomsoft      NewState(fp, ST_OPENED);
52269800Stomsoft      if ((*fp->fn->LayerUp)(fp))
52369800Stomsoft        (*fp->parent->LayerUp)(fp->parent->object, fp);
52469800Stomsoft      else {
52569800Stomsoft        (*fp->fn->LayerDown)(fp);
52669800Stomsoft        FsmInitRestartCounter(fp);
52798542Smckusick        FsmSendTerminateReq(fp);
52869926Stomsoft        NewState(fp, ST_CLOSING);
52969926Stomsoft      }
53069926Stomsoft    }
53169800Stomsoft    break;
53269800Stomsoft  case ST_ACKSENT:
53369800Stomsoft    if (!ackaction)
53469800Stomsoft      NewState(fp, ST_REQSENT);
53569800Stomsoft    break;
53669800Stomsoft  }
53769800Stomsoft  mbuf_Free(bp);
538114067Sschweikh}
53969800Stomsoft
540114067Sschweikhstatic void
541108470SschweikhFsmRecvConfigAck(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp)
54269800Stomsoft/* RCA */
54369800Stomsoft{
54498542Smckusick  switch (fp->state) {
54569800Stomsoft    case ST_CLOSED:
54669800Stomsoft    case ST_STOPPED:
54769800Stomsoft    (*fp->fn->SendTerminateAck)(fp, lhp->id);
54869800Stomsoft    break;
54969800Stomsoft  case ST_CLOSING:
55069800Stomsoft  case ST_STOPPING:
55169800Stomsoft    break;
55269800Stomsoft  case ST_REQSENT:
55369800Stomsoft    FsmInitRestartCounter(fp);
55469800Stomsoft    NewState(fp, ST_ACKRCVD);
55569800Stomsoft    break;
55669800Stomsoft  case ST_ACKRCVD:
557114067Sschweikh    FsmSendConfigReq(fp);
55869800Stomsoft    NewState(fp, ST_REQSENT);
55969800Stomsoft    break;
56069800Stomsoft  case ST_ACKSENT:
561114067Sschweikh    FsmInitRestartCounter(fp);
56269800Stomsoft    NewState(fp, ST_OPENED);
56369800Stomsoft    if ((*fp->fn->LayerUp)(fp))
56469800Stomsoft      (*fp->parent->LayerUp)(fp->parent->object, fp);
56569800Stomsoft    else {
56669800Stomsoft      (*fp->fn->LayerDown)(fp);
56769800Stomsoft      FsmInitRestartCounter(fp);
56869800Stomsoft      FsmSendTerminateReq(fp);
56969800Stomsoft      NewState(fp, ST_CLOSING);
57069800Stomsoft    }
57169926Stomsoft    break;
57269926Stomsoft  case ST_OPENED:
57369926Stomsoft    (*fp->fn->LayerDown)(fp);
57469800Stomsoft    FsmSendConfigReq(fp);
57569800Stomsoft    NewState(fp, ST_REQSENT);
57669800Stomsoft    (*fp->parent->LayerDown)(fp->parent->object, fp);
57769800Stomsoft    break;
57869800Stomsoft  }
57969800Stomsoft  mbuf_Free(bp);
58069800Stomsoft}
58169800Stomsoft
58269800Stomsoftstatic void
58369926StomsoftFsmRecvConfigNak(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp)
58469926Stomsoft/* RCN */
58569926Stomsoft{
58669800Stomsoft  struct fsm_decode dec;
58769926Stomsoft  int plen, flen;
58869926Stomsoft
58969926Stomsoft  plen = mbuf_Length(bp);
59069800Stomsoft  flen = ntohs(lhp->length) - sizeof *lhp;
59169800Stomsoft  if (plen < flen) {
59269800Stomsoft    mbuf_Free(bp);
59369800Stomsoft    return;
59469800Stomsoft  }
59569800Stomsoft
59669800Stomsoft  /*
59769800Stomsoft   * Check and process easy case
598114067Sschweikh   */
599114067Sschweikh  switch (fp->state) {
600114067Sschweikh  case ST_INITIAL:
60169800Stomsoft  case ST_STARTING:
60269800Stomsoft    log_Printf(fp->LogLevel, "%s: Oops, RCN in %s.\n",
60369800Stomsoft              fp->link->name, State2Nam(fp->state));
60498542Smckusick    mbuf_Free(bp);
60598542Smckusick    return;
60698542Smckusick  case ST_CLOSED:
60769800Stomsoft  case ST_STOPPED:
60869800Stomsoft    (*fp->fn->SendTerminateAck)(fp, lhp->id);
60998542Smckusick    mbuf_Free(bp);
61098542Smckusick    return;
61198542Smckusick  case ST_CLOSING:
61298542Smckusick  case ST_STOPPING:
61369800Stomsoft    mbuf_Free(bp);
61469800Stomsoft    return;
61569800Stomsoft  }
61698542Smckusick
61798542Smckusick  dec.ackend = dec.ack;
61898542Smckusick  dec.nakend = dec.nak;
61998542Smckusick  dec.rejend = dec.rej;
62098542Smckusick  (*fp->fn->DecodeConfig)(fp, MBUF_CTOP(bp), flen, MODE_NAK, &dec);
62198542Smckusick  if (flen < sizeof(struct fsmconfig))
62298542Smckusick    log_Printf(fp->LogLevel, "  [EMPTY]\n");
62398542Smckusick
62498542Smckusick  switch (fp->state) {
62598542Smckusick  case ST_REQSENT:
62698542Smckusick  case ST_ACKSENT:
62798542Smckusick    FsmInitRestartCounter(fp);
62898542Smckusick    FsmSendConfigReq(fp);
62998542Smckusick    break;
63098542Smckusick  case ST_OPENED:
63198542Smckusick    (*fp->fn->LayerDown)(fp);
63269800Stomsoft    FsmSendConfigReq(fp);
63398542Smckusick    NewState(fp, ST_REQSENT);
63498542Smckusick    (*fp->parent->LayerDown)(fp->parent->object, fp);
63598542Smckusick    break;
63698542Smckusick  case ST_ACKRCVD:
63798542Smckusick    FsmSendConfigReq(fp);
63898542Smckusick    NewState(fp, ST_REQSENT);
63998542Smckusick    break;
64098542Smckusick  }
64198542Smckusick
64298542Smckusick  mbuf_Free(bp);
64398542Smckusick}
64498542Smckusick
64598542Smckusickstatic void
64698542SmckusickFsmRecvTermReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp)
64798542Smckusick/* RTR */
64898542Smckusick{
64998542Smckusick  switch (fp->state) {
65098542Smckusick  case ST_INITIAL:
65169800Stomsoft  case ST_STARTING:
65269800Stomsoft    log_Printf(fp->LogLevel, "%s: Oops, RTR in %s\n",
65369800Stomsoft              fp->link->name, State2Nam(fp->state));
65498542Smckusick    break;
65569800Stomsoft  case ST_CLOSED:
65669800Stomsoft  case ST_STOPPED:
65769800Stomsoft  case ST_CLOSING:
65869800Stomsoft  case ST_STOPPING:
65969800Stomsoft  case ST_REQSENT:
660114067Sschweikh    (*fp->fn->SendTerminateAck)(fp, lhp->id);
661114067Sschweikh    break;
662114067Sschweikh  case ST_ACKRCVD:
66369800Stomsoft  case ST_ACKSENT:
664114067Sschweikh    (*fp->fn->SendTerminateAck)(fp, lhp->id);
665114067Sschweikh    NewState(fp, ST_REQSENT);
666114067Sschweikh    break;
66769800Stomsoft  case ST_OPENED:
66869800Stomsoft    (*fp->fn->LayerDown)(fp);
66969800Stomsoft    (*fp->fn->SendTerminateAck)(fp, lhp->id);
67077885Stomsoft    FsmInitRestartCounter(fp);
67169800Stomsoft    timer_Start(&fp->FsmTimer);	/* Start restart timer */
67269800Stomsoft    fp->restart = 0;
67398542Smckusick    NewState(fp, ST_STOPPING);
67469800Stomsoft    (*fp->parent->LayerDown)(fp->parent->object, fp);
67569800Stomsoft    break;
67669800Stomsoft  }
67769800Stomsoft  mbuf_Free(bp);
67869800Stomsoft}
67969800Stomsoft
68069800Stomsoftstatic void
68169800StomsoftFsmRecvTermAck(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp)
68269800Stomsoft/* RTA */
68369800Stomsoft{
68477885Stomsoft  switch (fp->state) {
68577885Stomsoft  case ST_CLOSING:
68669800Stomsoft    (*fp->fn->LayerFinish)(fp);
68769926Stomsoft    NewState(fp, ST_CLOSED);
68869926Stomsoft    (*fp->parent->LayerFinish)(fp->parent->object, fp);
68969926Stomsoft    break;
69069800Stomsoft  case ST_STOPPING:
69169800Stomsoft    (*fp->fn->LayerFinish)(fp);
69269800Stomsoft    NewState(fp, ST_STOPPED);
69369800Stomsoft    (*fp->parent->LayerFinish)(fp->parent->object, fp);
694114067Sschweikh    break;
69569800Stomsoft  case ST_ACKRCVD:
69669800Stomsoft    NewState(fp, ST_REQSENT);
697114067Sschweikh    break;
69869800Stomsoft  case ST_OPENED:
699114067Sschweikh    (*fp->fn->LayerDown)(fp);
70069800Stomsoft    FsmSendConfigReq(fp);
70169800Stomsoft    NewState(fp, ST_REQSENT);
70298542Smckusick    (*fp->parent->LayerDown)(fp->parent->object, fp);
70398542Smckusick    break;
70469800Stomsoft  }
70577885Stomsoft  mbuf_Free(bp);
70677885Stomsoft}
70769800Stomsoft
70869926Stomsoftstatic void
70969926StomsoftFsmRecvConfigRej(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp)
71069926Stomsoft/* RCJ */
71169800Stomsoft{
71269800Stomsoft  struct fsm_decode dec;
71369800Stomsoft  int plen, flen;
71469800Stomsoft
71569800Stomsoft  plen = mbuf_Length(bp);
71669800Stomsoft  flen = ntohs(lhp->length) - sizeof *lhp;
71769800Stomsoft  if (plen < flen) {
71869800Stomsoft    mbuf_Free(bp);
71969800Stomsoft    return;
72069800Stomsoft  }
72169800Stomsoft
72269800Stomsoft  /*
72369800Stomsoft   * Check and process easy case
72477885Stomsoft   */
72569800Stomsoft  switch (fp->state) {
72669800Stomsoft  case ST_INITIAL:
72769800Stomsoft  case ST_STARTING:
72869800Stomsoft    log_Printf(fp->LogLevel, "%s: Oops, RCJ in %s.\n",
72969800Stomsoft              fp->link->name, State2Nam(fp->state));
73069800Stomsoft    mbuf_Free(bp);
73169800Stomsoft    return;
73269800Stomsoft  case ST_CLOSED:
73369800Stomsoft  case ST_STOPPED:
73469800Stomsoft    (*fp->fn->SendTerminateAck)(fp, lhp->id);
73569800Stomsoft    mbuf_Free(bp);
73669800Stomsoft    return;
73769800Stomsoft  case ST_CLOSING:
73869800Stomsoft  case ST_STOPPING:
73969800Stomsoft    mbuf_Free(bp);
74069800Stomsoft    return;
74169800Stomsoft  }
74298542Smckusick
74398542Smckusick  dec.ackend = dec.ack;
74498542Smckusick  dec.nakend = dec.nak;
74569800Stomsoft  dec.rejend = dec.rej;
74698542Smckusick  (*fp->fn->DecodeConfig)(fp, MBUF_CTOP(bp), flen, MODE_REJ, &dec);
74769800Stomsoft  if (flen < sizeof(struct fsmconfig))
74898542Smckusick    log_Printf(fp->LogLevel, "  [EMPTY]\n");
74969926Stomsoft
75098542Smckusick  switch (fp->state) {
75198542Smckusick  case ST_REQSENT:
75298542Smckusick  case ST_ACKSENT:
75398542Smckusick    FsmInitRestartCounter(fp);
75498542Smckusick    FsmSendConfigReq(fp);
75598542Smckusick    break;
75669800Stomsoft  case ST_OPENED:
75769800Stomsoft    (*fp->fn->LayerDown)(fp);
75869800Stomsoft    FsmSendConfigReq(fp);
75969800Stomsoft    NewState(fp, ST_REQSENT);
76069800Stomsoft    (*fp->parent->LayerDown)(fp->parent->object, fp);
76169800Stomsoft    break;
76269800Stomsoft  case ST_ACKRCVD:
763114067Sschweikh    FsmSendConfigReq(fp);
764114067Sschweikh    NewState(fp, ST_REQSENT);
765114067Sschweikh    break;
766114067Sschweikh  }
767114067Sschweikh  mbuf_Free(bp);
768102231Strhodes}
76969800Stomsoft
77069800Stomsoftstatic void
77169800StomsoftFsmRecvCodeRej(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp)
77269800Stomsoft{
77369800Stomsoft  mbuf_Free(bp);
77469800Stomsoft}
77569800Stomsoft
77669800Stomsoftstatic void
77769800StomsoftFsmRecvProtoRej(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp)
77869800Stomsoft{
77969800Stomsoft  struct physical *p = link2physical(fp->link);
78069800Stomsoft  u_short *sp, proto;
78169800Stomsoft
78269800Stomsoft  sp = (u_short *)MBUF_CTOP(bp);
78369800Stomsoft  proto = ntohs(*sp);
78469800Stomsoft  log_Printf(fp->LogLevel, "%s: -- Protocol 0x%04x (%s) was rejected!\n",
78569800Stomsoft            fp->link->name, proto, hdlc_Protocol2Nam(proto));
78669800Stomsoft
78769800Stomsoft  switch (proto) {
78869800Stomsoft  case PROTO_LQR:
78969800Stomsoft    if (p)
790114067Sschweikh      lqr_Stop(p, LQM_LQR);
79169800Stomsoft    else
792102231Strhodes      log_Printf(LogERROR, "%s: FsmRecvProtoRej: Not a physical link !\n",
79369800Stomsoft                fp->link->name);
79469800Stomsoft    break;
79569800Stomsoft  case PROTO_CCP:
79669800Stomsoft    if (fp->proto == PROTO_LCP) {
79769800Stomsoft      fp = &fp->link->ccp.fsm;
798114067Sschweikh      (*fp->fn->LayerFinish)(fp);
79969800Stomsoft      switch (fp->state) {
80069800Stomsoft      case ST_CLOSED:
80169800Stomsoft      case ST_CLOSING:
80269800Stomsoft        NewState(fp, ST_CLOSED);
80369800Stomsoft      default:
80469800Stomsoft        NewState(fp, ST_STOPPED);
80569800Stomsoft        break;
80669800Stomsoft      }
80769800Stomsoft      (*fp->parent->LayerFinish)(fp->parent->object, fp);
80869800Stomsoft    }
80969800Stomsoft    break;
81069800Stomsoft  case PROTO_MP:
81169800Stomsoft    if (fp->proto == PROTO_LCP) {
81269800Stomsoft      struct lcp *lcp = fsm2lcp(fp);
81369800Stomsoft
81469800Stomsoft      if (lcp->want_mrru && lcp->his_mrru) {
81569800Stomsoft        log_Printf(LogPHASE, "%s: MP protocol reject is fatal !\n",
81669800Stomsoft                  fp->link->name);
81769800Stomsoft        fsm_Close(fp);
81869800Stomsoft      }
81969800Stomsoft    }
82069800Stomsoft    break;
82169800Stomsoft  }
82269800Stomsoft  mbuf_Free(bp);
82369800Stomsoft}
82469800Stomsoft
82569800Stomsoftstatic void
82669800StomsoftFsmRecvEchoReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp)
82769800Stomsoft{
82869800Stomsoft  struct lcp *lcp = fsm2lcp(fp);
82969800Stomsoft  u_char *cp;
83069800Stomsoft  u_int32_t magic;
83169800Stomsoft
83269800Stomsoft  if (lcp) {
83369800Stomsoft    cp = MBUF_CTOP(bp);
83469800Stomsoft    magic = ntohl(*(u_int32_t *)cp);
83569800Stomsoft    if (magic != lcp->his_magic) {
83669800Stomsoft      log_Printf(fp->LogLevel, "%s: RecvEchoReq: Error: His magic is bad!!\n",
83769800Stomsoft                fp->link->name);
83869800Stomsoft      /* XXX: We should send terminate request */
83969800Stomsoft    }
84069800Stomsoft    if (fp->state == ST_OPENED) {
84169800Stomsoft      *(u_int32_t *)cp = htonl(lcp->want_magic); /* local magic */
84269800Stomsoft      fsm_Output(fp, CODE_ECHOREP, lhp->id, cp, mbuf_Length(bp));
84369800Stomsoft    }
84469800Stomsoft  }
84569800Stomsoft  mbuf_Free(bp);
84669800Stomsoft}
84769800Stomsoft
84869800Stomsoftstatic void
84969800StomsoftFsmRecvEchoRep(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp)
85069800Stomsoft{
85169800Stomsoft  struct lcp *lcp = fsm2lcp(fp);
85269800Stomsoft  u_int32_t magic;
85369800Stomsoft
85469800Stomsoft  if (lcp) {
85569800Stomsoft    magic = ntohl(*(u_int32_t *)MBUF_CTOP(bp));
85669800Stomsoft    /* Tolerate echo replies with either magic number */
85769800Stomsoft    if (magic != 0 && magic != lcp->his_magic && magic != lcp->want_magic) {
85869800Stomsoft      log_Printf(LogWARN,
85969800Stomsoft                "%s: RecvEchoRep: Bad magic: expected 0x%08x, got: 0x%08x\n",
86069800Stomsoft	        fp->link->name, lcp->his_magic, magic);
86169800Stomsoft      /*
86269800Stomsoft       * XXX: We should send terminate request. But poor implementations may
86369800Stomsoft       * die as a result.
86469800Stomsoft       */
86569800Stomsoft    }
86669800Stomsoft    lqr_RecvEcho(fp, bp);
867114067Sschweikh  }
86869800Stomsoft  mbuf_Free(bp);
86969800Stomsoft}
87069800Stomsoft
87169800Stomsoftstatic void
87269800StomsoftFsmRecvDiscReq(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp)
87369800Stomsoft{
87469800Stomsoft  mbuf_Free(bp);
87569800Stomsoft}
87669800Stomsoft
87769800Stomsoftstatic void
87869800StomsoftFsmRecvIdent(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp)
87969800Stomsoft{
88069800Stomsoft  mbuf_Free(bp);
88169800Stomsoft}
88269800Stomsoft
88369800Stomsoftstatic void
88469800StomsoftFsmRecvTimeRemain(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp)
88569800Stomsoft{
88669800Stomsoft  mbuf_Free(bp);
88769800Stomsoft}
88869800Stomsoft
88969800Stomsoftstatic void
89069800StomsoftFsmRecvResetReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp)
89169800Stomsoft{
89269800Stomsoft  (*fp->fn->RecvResetReq)(fp);
89369800Stomsoft  /*
89477885Stomsoft   * All sendable compressed packets are queued in the PRI_NORMAL modem
89577885Stomsoft   * output queue.... dump 'em to the priority queue so that they arrive
89669800Stomsoft   * at the peer before our ResetAck.
89769926Stomsoft   */
89869926Stomsoft  link_SequenceQueue(fp->link);
89969926Stomsoft  fsm_Output(fp, CODE_RESETACK, lhp->id, NULL, 0);
90069800Stomsoft  mbuf_Free(bp);
90169800Stomsoft}
90269800Stomsoft
90369800Stomsoftstatic void
90469800StomsoftFsmRecvResetAck(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp)
90569800Stomsoft{
90669800Stomsoft  (*fp->fn->RecvResetAck)(fp, lhp->id);
907114067Sschweikh  mbuf_Free(bp);
90869800Stomsoft}
909114067Sschweikh
91069800Stomsoftvoid
91169800Stomsoftfsm_Input(struct fsm *fp, struct mbuf *bp)
912114067Sschweikh{
913114067Sschweikh  int len;
914114067Sschweikh  struct fsmheader *lhp;
91569800Stomsoft  const struct fsmcodedesc *codep;
916114067Sschweikh
91769800Stomsoft  len = mbuf_Length(bp);
918114067Sschweikh  if (len < sizeof(struct fsmheader)) {
919114067Sschweikh    mbuf_Free(bp);
92069800Stomsoft    return;
92169800Stomsoft  }
92269800Stomsoft  lhp = (struct fsmheader *) MBUF_CTOP(bp);
92377885Stomsoft  if (lhp->code < fp->min_code || lhp->code > fp->max_code ||
92469800Stomsoft      lhp->code > sizeof FsmCodes / sizeof *FsmCodes) {
92569800Stomsoft    /*
92669800Stomsoft     * Use a private id.  This is really a response-type packet, but we
92769800Stomsoft     * MUST send a unique id for each REQ....
92869800Stomsoft     */
92998542Smckusick    static u_char id;
93069800Stomsoft
93169800Stomsoft    fsm_Output(fp, CODE_CODEREJ, id++, MBUF_CTOP(bp), bp->cnt);
93269800Stomsoft    mbuf_Free(bp);
93369800Stomsoft    return;
93469800Stomsoft  }
93569800Stomsoft  bp->offset += sizeof(struct fsmheader);
93669800Stomsoft  bp->cnt -= sizeof(struct fsmheader);
93769800Stomsoft
93869800Stomsoft  codep = FsmCodes + lhp->code - 1;
93969800Stomsoft  if (lhp->id != fp->reqid && codep->check_reqid &&
94069800Stomsoft      Enabled(fp->bundle, OPT_IDCHECK)) {
94169800Stomsoft    log_Printf(fp->LogLevel, "%s: Recv%s(%d), dropped (expected %d)\n",
94269800Stomsoft	      fp->link->name, codep->name, lhp->id, fp->reqid);
94369800Stomsoft    return;
94469800Stomsoft  }
94569800Stomsoft
94669800Stomsoft  log_Printf(fp->LogLevel, "%s: Recv%s(%d) state = %s\n",
94769800Stomsoft	    fp->link->name, codep->name, lhp->id, State2Nam(fp->state));
94869800Stomsoft
94969800Stomsoft  if (log_IsKept(LogDEBUG))
95069800Stomsoft    mbuf_Log();
95169800Stomsoft
95269800Stomsoft  if (codep->inc_reqid && (lhp->id == fp->reqid ||
95369800Stomsoft      (!Enabled(fp->bundle, OPT_IDCHECK) && codep->check_reqid)))
95481311Schm    fp->reqid++;	/* That's the end of that ``exchange''.... */
95581311Schm
95681311Schm  (*codep->recv)(fp, lhp, bp);
95769800Stomsoft
95877885Stomsoft  if (log_IsKept(LogDEBUG))
95977885Stomsoft    mbuf_Log();
96069800Stomsoft}
96169926Stomsoft
96269926Stomsoftvoid
96369926Stomsoftfsm_NullRecvResetReq(struct fsm *fp)
96469800Stomsoft{
96569800Stomsoft  log_Printf(fp->LogLevel, "%s: Oops - received unexpected reset req\n",
96669800Stomsoft            fp->link->name);
96769800Stomsoft}
96869800Stomsoft
96969800Stomsoftvoid
97069800Stomsoftfsm_NullRecvResetAck(struct fsm *fp, u_char id)
97169800Stomsoft{
97269800Stomsoft  log_Printf(fp->LogLevel, "%s: Oops - received unexpected reset ack\n",
97369800Stomsoft            fp->link->name);
97469800Stomsoft}
975114067Sschweikh
976114067Sschweikhvoid
97769800Stomsoftfsm_Reopen(struct fsm *fp)
97869800Stomsoft{
97969800Stomsoft  if (fp->state == ST_OPENED) {
98069800Stomsoft    (*fp->fn->LayerDown)(fp);
981114067Sschweikh    FsmInitRestartCounter(fp);
982114067Sschweikh    FsmSendConfigReq(fp);
983114067Sschweikh    NewState(fp, ST_REQSENT);
98469800Stomsoft    (*fp->parent->LayerDown)(fp->parent->object, fp);
985114067Sschweikh  }
986114067Sschweikh}
98769800Stomsoft
98869800Stomsoftvoid
989114067Sschweikhfsm2initial(struct fsm *fp)
990114067Sschweikh{
991114067Sschweikh  if (fp->state == ST_STOPPED)
99269800Stomsoft    fsm_Close(fp);
993114067Sschweikh  if (fp->state > ST_INITIAL)
99469800Stomsoft    fsm_Down(fp);
995114067Sschweikh  if (fp->state > ST_INITIAL)
99669800Stomsoft    fsm_Close(fp);
99769800Stomsoft}
99869800Stomsoft