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