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