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