fsm.c revision 32381
1/*
2 *		PPP Finite State Machine for LCP/IPCP
3 *
4 *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
5 *
6 *   Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
7 *
8 * Redistribution and use in source and binary forms are permitted
9 * provided that the above copyright notice and this paragraph are
10 * duplicated in all such forms and that any documentation,
11 * advertising materials, and other materials related to such
12 * distribution and use acknowledge that the software was developed
13 * by the Internet Initiative Japan, Inc.  The name of the
14 * IIJ may not be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19 *
20 * $Id: fsm.c,v 1.25 1997/12/24 09:28:58 brian Exp $
21 *
22 *  TODO:
23 *		o Refer loglevel for log output
24 *		o Better option log display
25 */
26#include <sys/param.h>
27#include <netinet/in.h>
28
29#include <stdio.h>
30#include <string.h>
31#include <termios.h>
32
33#include "command.h"
34#include "mbuf.h"
35#include "log.h"
36#include "defs.h"
37#include "timer.h"
38#include "fsm.h"
39#include "hdlc.h"
40#include "lqr.h"
41#include "lcpproto.h"
42#include "lcp.h"
43#include "ccp.h"
44#include "modem.h"
45#include "loadalias.h"
46#include "vars.h"
47
48u_char AckBuff[200];
49u_char NakBuff[200];
50u_char RejBuff[100];
51u_char ReqBuff[200];
52u_char *ackp = NULL;
53u_char *nakp = NULL;
54u_char *rejp = NULL;
55
56static void FsmSendConfigReq(struct fsm *);
57static void FsmSendTerminateReq(struct fsm *);
58static void FsmInitRestartCounter(struct fsm *);
59
60char const *StateNames[] = {
61  "Initial", "Starting", "Closed", "Stopped", "Closing", "Stopping",
62  "Req-Sent", "Ack-Rcvd", "Ack-Sent", "Opened",
63};
64
65static void
66StoppedTimeout(void *v)
67{
68  struct fsm *fp = (struct fsm *)v;
69
70  LogPrintf(fp->LogLevel, "Stopped timer expired\n");
71  if (modem != -1)
72    DownConnection();
73  else
74    FsmDown(fp);
75}
76
77void
78FsmInit(struct fsm * fp)
79{
80  LogPrintf(LogDEBUG, "FsmInit\n");
81  fp->state = ST_INITIAL;
82  fp->reqid = 1;
83  fp->restart = 1;
84  fp->maxconfig = 3;
85}
86
87static void
88NewState(struct fsm * fp, int new)
89{
90  LogPrintf(fp->LogLevel, "State change %s --> %s\n",
91	    StateNames[fp->state], StateNames[new]);
92  if (fp->state == ST_STOPPED && fp->StoppedTimer.state == TIMER_RUNNING)
93    StopTimer(&fp->StoppedTimer);
94  fp->state = new;
95  if ((new >= ST_INITIAL && new <= ST_STOPPED) || (new == ST_OPENED)) {
96    StopTimer(&fp->FsmTimer);
97    if (new == ST_STOPPED && fp->StoppedTimer.load) {
98      fp->StoppedTimer.state = TIMER_STOPPED;
99      fp->StoppedTimer.func = StoppedTimeout;
100      fp->StoppedTimer.arg = (void *) fp;
101      StartTimer(&fp->StoppedTimer);
102    }
103  }
104}
105
106void
107FsmOutput(struct fsm * fp, u_int code, u_int id, u_char * ptr, int count)
108{
109  int plen;
110  struct fsmheader lh;
111  struct mbuf *bp;
112
113  plen = sizeof(struct fsmheader) + count;
114  lh.code = code;
115  lh.id = id;
116  lh.length = htons(plen);
117  bp = mballoc(plen, MB_FSM);
118  memcpy(MBUF_CTOP(bp), &lh, sizeof(struct fsmheader));
119  if (count)
120    memcpy(MBUF_CTOP(bp) + sizeof(struct fsmheader), ptr, count);
121  LogDumpBp(LogDEBUG, "FsmOutput", bp);
122  HdlcOutput(PRI_LINK, fp->proto, bp);
123}
124
125void
126FsmOpen(struct fsm * fp)
127{
128  switch (fp->state) {
129    case ST_INITIAL:
130    (fp->LayerStart) (fp);
131    NewState(fp, ST_STARTING);
132    break;
133  case ST_STARTING:
134    break;
135  case ST_CLOSED:
136    if (fp->open_mode == OPEN_PASSIVE) {
137      NewState(fp, ST_STOPPED);
138    } else {
139      FsmInitRestartCounter(fp);
140      FsmSendConfigReq(fp);
141      NewState(fp, ST_REQSENT);
142    }
143    break;
144  case ST_STOPPED:		/* XXX: restart option */
145  case ST_REQSENT:
146  case ST_ACKRCVD:
147  case ST_ACKSENT:
148  case ST_OPENED:		/* XXX: restart option */
149    break;
150  case ST_CLOSING:		/* XXX: restart option */
151  case ST_STOPPING:		/* XXX: restart option */
152    NewState(fp, ST_STOPPING);
153    break;
154  }
155}
156
157void
158FsmUp(struct fsm * fp)
159{
160  switch (fp->state) {
161    case ST_INITIAL:
162    NewState(fp, ST_CLOSED);
163    break;
164  case ST_STARTING:
165    FsmInitRestartCounter(fp);
166    FsmSendConfigReq(fp);
167    NewState(fp, ST_REQSENT);
168    break;
169  default:
170    LogPrintf(fp->LogLevel, "Oops, Up at %s\n", StateNames[fp->state]);
171    break;
172  }
173}
174
175void
176FsmDown(struct fsm * fp)
177{
178  switch (fp->state) {
179    case ST_CLOSED:
180    case ST_CLOSING:
181    NewState(fp, ST_INITIAL);
182    break;
183  case ST_STOPPED:
184    (fp->LayerStart) (fp);
185    /* Fall into.. */
186  case ST_STOPPING:
187  case ST_REQSENT:
188  case ST_ACKRCVD:
189  case ST_ACKSENT:
190    NewState(fp, ST_STARTING);
191    break;
192  case ST_OPENED:
193    (fp->LayerDown) (fp);
194    NewState(fp, ST_STARTING);
195    break;
196  }
197}
198
199void
200FsmClose(struct fsm * fp)
201{
202  switch (fp->state) {
203    case ST_STARTING:
204    NewState(fp, ST_INITIAL);
205    break;
206  case ST_STOPPED:
207    NewState(fp, ST_CLOSED);
208    break;
209  case ST_STOPPING:
210    NewState(fp, ST_CLOSING);
211    break;
212  case ST_OPENED:
213    (fp->LayerDown) (fp);
214    /* Fall down */
215  case ST_REQSENT:
216  case ST_ACKRCVD:
217  case ST_ACKSENT:
218    FsmInitRestartCounter(fp);
219    FsmSendTerminateReq(fp);
220    NewState(fp, ST_CLOSING);
221    break;
222  }
223}
224
225/*
226 *	Send functions
227 */
228static void
229FsmSendConfigReq(struct fsm * fp)
230{
231  if (--fp->maxconfig > 0) {
232    (fp->SendConfigReq) (fp);
233    StartTimer(&fp->FsmTimer);	/* Start restart timer */
234    fp->restart--;		/* Decrement restart counter */
235  } else {
236    FsmClose(fp);
237  }
238}
239
240static void
241FsmSendTerminateReq(struct fsm * fp)
242{
243  LogPrintf(fp->LogLevel, "SendTerminateReq.\n");
244  FsmOutput(fp, CODE_TERMREQ, fp->reqid++, NULL, 0);
245  (fp->SendTerminateReq) (fp);
246  StartTimer(&fp->FsmTimer);	/* Start restart timer */
247  fp->restart--;		/* Decrement restart counter */
248}
249
250static void
251FsmSendConfigAck(struct fsm * fp,
252		 struct fsmheader * lhp,
253		 u_char * option,
254		 int count)
255{
256  LogPrintf(fp->LogLevel, "SendConfigAck(%s)\n", StateNames[fp->state]);
257  (fp->DecodeConfig) (option, count, MODE_NOP);
258  FsmOutput(fp, CODE_CONFIGACK, lhp->id, option, count);
259}
260
261static void
262FsmSendConfigRej(struct fsm * fp,
263		 struct fsmheader * lhp,
264		 u_char * option,
265		 int count)
266{
267  LogPrintf(fp->LogLevel, "SendConfigRej(%s)\n", StateNames[fp->state]);
268  (fp->DecodeConfig) (option, count, MODE_NOP);
269  FsmOutput(fp, CODE_CONFIGREJ, lhp->id, option, count);
270}
271
272static void
273FsmSendConfigNak(struct fsm * fp,
274		 struct fsmheader * lhp,
275		 u_char * option,
276		 int count)
277{
278  LogPrintf(fp->LogLevel, "SendConfigNak(%s)\n", StateNames[fp->state]);
279  (fp->DecodeConfig) (option, count, MODE_NOP);
280  FsmOutput(fp, CODE_CONFIGNAK, lhp->id, option, count);
281}
282
283/*
284 *	Timeout actions
285 */
286static void
287FsmTimeout(void *v)
288{
289  struct fsm *fp = (struct fsm *)v;
290
291  if (fp->restart) {
292    switch (fp->state) {
293      case ST_CLOSING:
294      case ST_STOPPING:
295      FsmSendTerminateReq(fp);
296      break;
297    case ST_REQSENT:
298    case ST_ACKSENT:
299      FsmSendConfigReq(fp);
300      break;
301    case ST_ACKRCVD:
302      FsmSendConfigReq(fp);
303      NewState(fp, ST_REQSENT);
304      break;
305    }
306    StartTimer(&fp->FsmTimer);
307  } else {
308    switch (fp->state) {
309    case ST_CLOSING:
310      NewState(fp, ST_CLOSED);
311      (fp->LayerFinish) (fp);
312      break;
313    case ST_STOPPING:
314      NewState(fp, ST_STOPPED);
315      (fp->LayerFinish) (fp);
316      break;
317    case ST_REQSENT:		/* XXX: 3p */
318    case ST_ACKSENT:
319    case ST_ACKRCVD:
320      NewState(fp, ST_STOPPED);
321      (fp->LayerFinish) (fp);
322      break;
323    }
324  }
325}
326
327static void
328FsmInitRestartCounter(struct fsm * fp)
329{
330  StopTimer(&fp->FsmTimer);
331  fp->FsmTimer.state = TIMER_STOPPED;
332  fp->FsmTimer.func = FsmTimeout;
333  fp->FsmTimer.arg = (void *) fp;
334  (fp->InitRestartCounter) (fp);
335}
336
337/*
338 *   Actions when receive packets
339 */
340static void
341FsmRecvConfigReq(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp)
342/* RCR */
343{
344  int plen, flen;
345  int ackaction = 0;
346
347  plen = plength(bp);
348  flen = ntohs(lhp->length) - sizeof *lhp;
349  if (plen < flen) {
350    LogPrintf(LogERROR, "FsmRecvConfigReq: plen (%d) < flen (%d)\n",
351	      plen, flen);
352    pfree(bp);
353    return;
354  }
355
356  /*
357   * Check and process easy case
358   */
359  switch (fp->state) {
360  case ST_INITIAL:
361  case ST_STARTING:
362    LogPrintf(fp->LogLevel, "Oops, RCR in %s.\n", StateNames[fp->state]);
363    pfree(bp);
364    return;
365  case ST_CLOSED:
366    (fp->SendTerminateAck) (fp);
367    pfree(bp);
368    return;
369  case ST_CLOSING:
370    LogPrintf(fp->LogLevel, "Error: Got ConfigReq while state = %d\n",
371              fp->state);
372  case ST_STOPPING:
373    pfree(bp);
374    return;
375  }
376
377  (fp->DecodeConfig) (MBUF_CTOP(bp), flen, MODE_REQ);
378
379  if (nakp == NakBuff && rejp == RejBuff)
380    ackaction = 1;
381
382  switch (fp->state) {
383  case ST_OPENED:
384    (fp->LayerDown) (fp);
385    FsmSendConfigReq(fp);
386    break;
387  case ST_STOPPED:
388    FsmInitRestartCounter(fp);
389    FsmSendConfigReq(fp);
390    break;
391  }
392
393  if (rejp != RejBuff)
394    FsmSendConfigRej(fp, lhp, RejBuff, rejp - RejBuff);
395  if (nakp != NakBuff)
396    FsmSendConfigNak(fp, lhp, NakBuff, nakp - NakBuff);
397  if (ackaction)
398    FsmSendConfigAck(fp, lhp, AckBuff, ackp - AckBuff);
399
400  switch (fp->state) {
401  case ST_STOPPED:
402  case ST_OPENED:
403    if (ackaction)
404      NewState(fp, ST_ACKSENT);
405    else
406      NewState(fp, ST_REQSENT);
407    break;
408  case ST_REQSENT:
409    if (ackaction)
410      NewState(fp, ST_ACKSENT);
411    break;
412  case ST_ACKRCVD:
413    if (ackaction) {
414      NewState(fp, ST_OPENED);
415      (fp->LayerUp) (fp);
416    }
417    break;
418  case ST_ACKSENT:
419    if (!ackaction)
420      NewState(fp, ST_REQSENT);
421    break;
422  }
423  pfree(bp);
424}
425
426static void
427FsmRecvConfigAck(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp)
428/* RCA */
429{
430  switch (fp->state) {
431    case ST_CLOSED:
432    case ST_STOPPED:
433    (fp->SendTerminateAck) (fp);
434    break;
435  case ST_CLOSING:
436  case ST_STOPPING:
437    break;
438  case ST_REQSENT:
439    FsmInitRestartCounter(fp);
440    NewState(fp, ST_ACKRCVD);
441    break;
442  case ST_ACKRCVD:
443    FsmSendConfigReq(fp);
444    NewState(fp, ST_REQSENT);
445    break;
446  case ST_ACKSENT:
447    FsmInitRestartCounter(fp);
448    NewState(fp, ST_OPENED);
449    (fp->LayerUp) (fp);
450    break;
451  case ST_OPENED:
452    (fp->LayerDown) (fp);
453    FsmSendConfigReq(fp);
454    NewState(fp, ST_REQSENT);
455    break;
456  }
457  pfree(bp);
458}
459
460static void
461FsmRecvConfigNak(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp)
462/* RCN */
463{
464  int plen, flen;
465
466  plen = plength(bp);
467  flen = ntohs(lhp->length) - sizeof *lhp;
468  if (plen < flen) {
469    pfree(bp);
470    return;
471  }
472
473  /*
474   * Check and process easy case
475   */
476  switch (fp->state) {
477  case ST_INITIAL:
478  case ST_STARTING:
479    LogPrintf(fp->LogLevel, "Oops, RCN in %s.\n", StateNames[fp->state]);
480    pfree(bp);
481    return;
482  case ST_CLOSED:
483  case ST_STOPPED:
484    (fp->SendTerminateAck) (fp);
485    pfree(bp);
486    return;
487  case ST_CLOSING:
488  case ST_STOPPING:
489    pfree(bp);
490    return;
491  }
492
493  (fp->DecodeConfig) (MBUF_CTOP(bp), flen, MODE_NAK);
494
495  switch (fp->state) {
496  case ST_REQSENT:
497  case ST_ACKSENT:
498    FsmInitRestartCounter(fp);
499    FsmSendConfigReq(fp);
500    break;
501  case ST_OPENED:
502    (fp->LayerDown) (fp);
503    /* Fall down */
504  case ST_ACKRCVD:
505    FsmSendConfigReq(fp);
506    NewState(fp, ST_REQSENT);
507    break;
508  }
509
510  pfree(bp);
511}
512
513static void
514FsmRecvTermReq(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp)
515/* RTR */
516{
517  switch (fp->state) {
518    case ST_INITIAL:
519    case ST_STARTING:
520    LogPrintf(fp->LogLevel, "Oops, RTR in %s\n", StateNames[fp->state]);
521    break;
522  case ST_CLOSED:
523  case ST_STOPPED:
524  case ST_CLOSING:
525  case ST_STOPPING:
526  case ST_REQSENT:
527    (fp->SendTerminateAck) (fp);
528    break;
529  case ST_ACKRCVD:
530  case ST_ACKSENT:
531    (fp->SendTerminateAck) (fp);
532    NewState(fp, ST_REQSENT);
533    break;
534  case ST_OPENED:
535    (fp->LayerDown) (fp);
536    (fp->SendTerminateAck) (fp);
537    StartTimer(&fp->FsmTimer);	/* Start restart timer */
538    fp->restart = 0;
539    NewState(fp, ST_STOPPING);
540    break;
541  }
542  pfree(bp);
543}
544
545static void
546FsmRecvTermAck(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp)
547/* RTA */
548{
549  switch (fp->state) {
550    case ST_CLOSING:
551    NewState(fp, ST_CLOSED);
552    (fp->LayerFinish) (fp);
553    break;
554  case ST_STOPPING:
555    NewState(fp, ST_STOPPED);
556    (fp->LayerFinish) (fp);
557    break;
558  case ST_ACKRCVD:
559    NewState(fp, ST_REQSENT);
560    break;
561  case ST_OPENED:
562    (fp->LayerDown) (fp);
563    FsmSendConfigReq(fp);
564    NewState(fp, ST_REQSENT);
565    break;
566  }
567  pfree(bp);
568}
569
570static void
571FsmRecvConfigRej(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp)
572/* RCJ */
573{
574  int plen, flen;
575
576  plen = plength(bp);
577  flen = ntohs(lhp->length) - sizeof *lhp;
578  if (plen < flen) {
579    pfree(bp);
580    return;
581  }
582  LogPrintf(fp->LogLevel, "RecvConfigRej.\n");
583
584  /*
585   * Check and process easy case
586   */
587  switch (fp->state) {
588  case ST_INITIAL:
589  case ST_STARTING:
590    LogPrintf(fp->LogLevel, "Oops, RCJ in %s.\n", StateNames[fp->state]);
591    pfree(bp);
592    return;
593  case ST_CLOSED:
594  case ST_STOPPED:
595    (fp->SendTerminateAck) (fp);
596    pfree(bp);
597    return;
598  case ST_CLOSING:
599  case ST_STOPPING:
600    pfree(bp);
601    return;
602  }
603
604  (fp->DecodeConfig) (MBUF_CTOP(bp), flen, MODE_REJ);
605
606  switch (fp->state) {
607  case ST_REQSENT:
608  case ST_ACKSENT:
609    FsmInitRestartCounter(fp);
610    FsmSendConfigReq(fp);
611    break;
612  case ST_OPENED:
613    (fp->LayerDown) (fp);
614    /* Fall down */
615  case ST_ACKRCVD:
616    FsmSendConfigReq(fp);
617    NewState(fp, ST_REQSENT);
618    break;
619  }
620  pfree(bp);
621}
622
623static void
624FsmRecvCodeRej(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp)
625{
626  LogPrintf(fp->LogLevel, "RecvCodeRej\n");
627  pfree(bp);
628}
629
630static void
631FsmRecvProtoRej(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp)
632{
633  u_short *sp, proto;
634
635  sp = (u_short *) MBUF_CTOP(bp);
636  proto = ntohs(*sp);
637  LogPrintf(fp->LogLevel, "-- Protocol (%04x) was rejected.\n", proto);
638
639  switch (proto) {
640  case PROTO_LQR:
641    StopLqr(LQM_LQR);
642    break;
643  case PROTO_CCP:
644    fp = &CcpFsm;
645    (fp->LayerFinish) (fp);
646    switch (fp->state) {
647    case ST_CLOSED:
648    case ST_CLOSING:
649      NewState(fp, ST_CLOSED);
650    default:
651      NewState(fp, ST_STOPPED);
652      break;
653    }
654    break;
655  }
656  pfree(bp);
657}
658
659static void
660FsmRecvEchoReq(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp)
661{
662  u_char *cp;
663  u_long *lp, magic;
664
665  cp = MBUF_CTOP(bp);
666  lp = (u_long *) cp;
667  magic = ntohl(*lp);
668  if (magic != LcpInfo.his_magic) {
669    LogPrintf(LogERROR, "RecvEchoReq: his magic is bad!!\n");
670    /* XXX: We should send terminate request */
671  }
672  if (fp->state == ST_OPENED) {
673    *lp = htonl(LcpInfo.want_magic);	/* Insert local magic number */
674    LogPrintf(fp->LogLevel, "SendEchoRep(%s)\n", StateNames[fp->state]);
675    FsmOutput(fp, CODE_ECHOREP, lhp->id, cp, plength(bp));
676  }
677  pfree(bp);
678}
679
680static void
681FsmRecvEchoRep(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp)
682{
683  u_long *lp, magic;
684
685  lp = (u_long *) MBUF_CTOP(bp);
686  magic = ntohl(*lp);
687/*
688 * Tolerate echo replies with either magic number
689 */
690  if (magic != 0 && magic != LcpInfo.his_magic && magic != LcpInfo.want_magic) {
691    LogPrintf(LogERROR, "RecvEchoRep: his magic is wrong! expect: %x got: %x\n",
692	      LcpInfo.his_magic, magic);
693
694    /*
695     * XXX: We should send terminate request. But poor implementation may die
696     * as a result.
697     */
698  }
699  RecvEchoLqr(bp);
700  pfree(bp);
701}
702
703static void
704FsmRecvDiscReq(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp)
705{
706  LogPrintf(fp->LogLevel, "RecvDiscReq\n");
707  pfree(bp);
708}
709
710static void
711FsmRecvIdent(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp)
712{
713  LogPrintf(fp->LogLevel, "RecvIdent\n");
714  pfree(bp);
715}
716
717static void
718FsmRecvTimeRemain(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp)
719{
720  LogPrintf(fp->LogLevel, "RecvTimeRemain\n");
721  pfree(bp);
722}
723
724static void
725FsmRecvResetReq(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp)
726{
727  LogPrintf(fp->LogLevel, "RecvResetReq(%d)\n", lhp->id);
728  CcpRecvResetReq(fp);
729  /*
730   * All sendable compressed packets are queued in the PRI_NORMAL modem
731   * output queue.... dump 'em to the priority queue so that they arrive
732   * at the peer before our ResetAck.
733   */
734  SequenceQueues();
735  LogPrintf(fp->LogLevel, "SendResetAck(%d)\n", lhp->id);
736  FsmOutput(fp, CODE_RESETACK, lhp->id, NULL, 0);
737  pfree(bp);
738}
739
740static void
741FsmRecvResetAck(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp)
742{
743  LogPrintf(fp->LogLevel, "RecvResetAck(%d)\n", lhp->id);
744  CcpResetInput(lhp->id);
745  fp->reqid++;
746  pfree(bp);
747}
748
749static const struct fsmcodedesc FsmCodes[] = {
750  {FsmRecvConfigReq, "Configure Request",},
751  {FsmRecvConfigAck, "Configure Ack",},
752  {FsmRecvConfigNak, "Configure Nak",},
753  {FsmRecvConfigRej, "Configure Reject",},
754  {FsmRecvTermReq, "Terminate Request",},
755  {FsmRecvTermAck, "Terminate Ack",},
756  {FsmRecvCodeRej, "Code Reject",},
757  {FsmRecvProtoRej, "Protocol Reject",},
758  {FsmRecvEchoReq, "Echo Request",},
759  {FsmRecvEchoRep, "Echo Reply",},
760  {FsmRecvDiscReq, "Discard Request",},
761  {FsmRecvIdent, "Ident",},
762  {FsmRecvTimeRemain, "Time Remain",},
763  {FsmRecvResetReq, "Reset Request",},
764  {FsmRecvResetAck, "Reset Ack",},
765};
766
767void
768FsmInput(struct fsm * fp, struct mbuf * bp)
769{
770  int len;
771  struct fsmheader *lhp;
772  const struct fsmcodedesc *codep;
773
774  len = plength(bp);
775  if (len < sizeof(struct fsmheader)) {
776    pfree(bp);
777    return;
778  }
779  lhp = (struct fsmheader *) MBUF_CTOP(bp);
780  if (lhp->code == 0 || lhp->code > fp->max_code) {
781    pfree(bp);			/* XXX: Should send code reject */
782    return;
783  }
784  bp->offset += sizeof(struct fsmheader);
785  bp->cnt -= sizeof(struct fsmheader);
786
787  codep = FsmCodes + lhp->code - 1;
788  LogPrintf(fp->LogLevel, "Received %s (%d) state = %s (%d)\n",
789	    codep->name, lhp->id, StateNames[fp->state], fp->state);
790  if (LogIsKept(LogDEBUG))
791    LogMemory();
792  (codep->action) (fp, lhp, bp);
793  if (LogIsKept(LogDEBUG))
794    LogMemory();
795}
796