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