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