xref: /freebsd/usr.sbin/ppp/fsm.c (revision 05c7a37afb48ddd5ee1bd921a5d46fe59cc70b15)
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.5 1996/01/11 17:48:44 phk 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 
33 void FsmSendConfigReq(struct fsm *fp);
34 void FsmSendTerminateReq(struct fsm *fp);
35 void FsmInitRestartCounter(struct fsm *fp);
36 void FsmTimeout(struct fsm *fp);
37 
38 char const *StateNames[] = {
39   "Initial", "Starting", "Closed", "Stopped", "Closing", "Stopping",
40   "Req-Sent", "Ack-Rcvd", "Ack-Sent", "Opend",
41 };
42 
43 void
44 FsmInit(fp)
45 struct 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 
56 void
57 NewState(fp, new)
58 struct fsm *fp;
59 int new;
60 {
61   LogPrintf(LOG_LCP, "%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 
68 void
69 FsmOutput(fp, code, id, ptr, count)
70 struct fsm *fp;
71 u_int code, id;
72 u_char *ptr;
73 int 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 
93 void
94 FsmOpen(fp)
95 struct 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 
126 void
127 FsmUp(fp)
128 struct 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, "%s: Oops, Up at %s\n",
141 	    fp->name, StateNames[fp->state]);
142     break;
143   }
144 }
145 
146 void
147 FsmDown(fp)
148 struct 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 
171 void
172 FsmClose(fp)
173 struct 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  */
201 void
202 FsmSendConfigReq(fp)
203 struct 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 
214 void
215 FsmSendTerminateReq(fp)
216 struct fsm *fp;
217 {
218   LogPrintf(LOG_LCP, "%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 
225 static void
226 FsmSendConfigAck(fp, lhp, option, count)
227 struct fsm *fp;
228 struct fsmheader *lhp;
229 u_char *option;
230 int count;
231 {
232   LogPrintf(LOG_LCP, "%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 
237 static void
238 FsmSendConfigRej(fp, lhp, option, count)
239 struct fsm *fp;
240 struct fsmheader *lhp;
241 u_char *option;
242 int count;
243 {
244   LogPrintf(LOG_LCP, "%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 
249 static void
250 FsmSendConfigNak(fp, lhp, option, count)
251 struct fsm *fp;
252 struct fsmheader *lhp;
253 u_char *option;
254 int count;
255 {
256   LogPrintf(LOG_LCP, "%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  */
265 void
266 FsmTimeout(fp)
267 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 
305 void
306 FsmInitRestartCounter(fp)
307 struct 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  */
319 void
320 FsmRecvConfigReq(fp, lhp, bp)			/* RCR */
321 struct fsm *fp;
322 struct fsmheader *lhp;
323 struct 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, "%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 
407 void
408 FsmRecvConfigAck(fp, lhp, bp)			/* RCA */
409 struct fsm *fp;
410 struct fsmheader *lhp;
411 struct 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 
443 void
444 FsmRecvConfigNak(fp, lhp, bp)			/* RCN */
445 struct fsm *fp;
446 struct fsmheader *lhp;
447 struct 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, "%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 
499 void
500 FsmRecvTermReq(fp, lhp, bp)				/* RTR */
501 struct fsm *fp;
502 struct fsmheader *lhp;
503 struct mbuf *bp;
504 {
505   switch (fp->state) {
506   case ST_INITIAL:
507   case ST_STARTING:
508     LogPrintf(LOG_LCP, "%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     /* Zero Restart counter */
526     (fp->SendTerminateAck)(fp);
527     NewState(fp, ST_STOPPING);
528     break;
529   }
530   pfree(bp);
531 }
532 
533 void
534 FsmRecvTermAck(fp, lhp, bp)			/* RTA */
535 struct fsm *fp;
536 struct fsmheader *lhp;
537 struct mbuf *bp;
538 {
539   switch (fp->state) {
540   case ST_CLOSING:
541     NewState(fp, ST_CLOSED);
542     (fp->LayerFinish)(fp);
543     break;
544   case ST_STOPPING:
545     NewState(fp, ST_STOPPED);
546     (fp->LayerFinish)(fp);
547     break;
548   case ST_ACKRCVD:
549     NewState(fp, ST_REQSENT);
550     break;
551   case ST_OPENED:
552     (fp->LayerDown)(fp);
553     FsmSendConfigReq(fp);
554     NewState(fp, ST_REQSENT);
555     break;
556   }
557   pfree(bp);
558 }
559 
560 void
561 FsmRecvConfigRej(fp, lhp, bp)			/* RCJ */
562 struct fsm *fp;
563 struct fsmheader *lhp;
564 struct mbuf *bp;
565 {
566   int plen, flen;
567 
568   plen = plength(bp);
569   flen = ntohs(lhp->length) - sizeof(*lhp);
570   if (plen < flen) {
571     pfree(bp);
572     return;
573   }
574   LogPrintf(LOG_LCP, "%s: RecvConfigRej.\n", fp->name);
575 
576   /*
577    *  Check and process easy case
578    */
579   switch (fp->state) {
580   case ST_INITIAL:
581   case ST_STARTING:
582     LogPrintf(LOG_LCP, "%s: Oops, RCJ in %s.\n",
583 	    fp->name, StateNames[fp->state]);
584     pfree(bp);
585     return;
586   case ST_CLOSED:
587   case ST_STOPPED:
588     (fp->SendTerminateAck)(fp);
589     pfree(bp);
590     return;
591   case ST_CLOSING:
592   case ST_STOPPING:
593     pfree(bp);
594     return;
595   }
596 
597   (fp->DecodeConfig)(MBUF_CTOP(bp), flen, MODE_REJ);
598 
599   switch (fp->state) {
600   case ST_REQSENT:
601   case ST_ACKSENT:
602     FsmInitRestartCounter(fp);
603     FsmSendConfigReq(fp);
604     break;
605   case ST_OPENED:
606     (fp->LayerDown)(fp);
607     /* Fall down */
608   case ST_ACKRCVD:
609     FsmSendConfigReq(fp);
610     NewState(fp, ST_REQSENT);
611     break;
612   }
613   pfree(bp);
614 }
615 
616 void
617 FsmRecvCodeRej(fp, lhp, bp)
618 struct fsm *fp;
619 struct fsmheader *lhp;
620 struct mbuf *bp;
621 {
622   LogPrintf(LOG_LCP, "%s: RecvCodeRej\n", fp->name);
623   pfree(bp);
624 }
625 
626 void
627 FsmRecvProtoRej(fp, lhp, bp)
628 struct fsm *fp;
629 struct fsmheader *lhp;
630 struct mbuf *bp;
631 {
632   u_short *sp, proto;
633 
634   sp = (u_short *)MBUF_CTOP(bp);
635   proto = ntohs(*sp);
636   LogPrintf(LOG_LCP, "-- Protocol (%04x) was rejected.\n", proto);
637 
638   switch (proto) {
639   case PROTO_LQR:
640     StopLqr(LQM_LQR);
641     break;
642   case PROTO_CCP:
643     fp = &CcpFsm;
644     (fp->LayerFinish)(fp);
645     switch (fp->state) {
646     case ST_CLOSED:
647     case ST_CLOSING:
648       NewState(fp, ST_CLOSED);
649     default:
650       NewState(fp, ST_STOPPED);
651       break;
652     }
653     break;
654   }
655   pfree(bp);
656 }
657 
658 void
659 FsmRecvEchoReq(fp, lhp, bp)
660 struct fsm *fp;
661 struct fsmheader *lhp;
662 struct mbuf *bp;
663 {
664   u_char *cp;
665   u_long *lp, magic;
666 
667   cp = MBUF_CTOP(bp);
668   lp = (u_long *)cp;
669   magic = ntohl(*lp);
670   if (magic != LcpInfo.his_magic) {
671     logprintf("RecvEchoReq: his magic is bad!!\n");
672     /* XXX: We should send terminate request */
673   }
674 
675   if (fp->state == ST_OPENED) {
676     *lp = htonl(LcpInfo.want_magic);	/* Insert local magic number */
677     LogPrintf(LOG_LCP, "%s:  SendEchoRep(%s)\n", fp->name, StateNames[fp->state]);
678     FsmOutput(fp, CODE_ECHOREP, lhp->id, cp, plength(bp));
679   }
680   pfree(bp);
681 }
682 
683 void
684 FsmRecvEchoRep(fp, lhp, bp)
685 struct fsm *fp;
686 struct fsmheader *lhp;
687 struct mbuf *bp;
688 {
689   u_long *lp, magic;
690 
691   lp = (u_long *)MBUF_CTOP(bp);
692   magic = ntohl(*lp);
693 /*
694  * Tolerate echo replies with either magic number
695  */
696   if (magic != 0 && magic != LcpInfo.his_magic && magic != LcpInfo.want_magic) {
697     logprintf("RecvEchoRep: his magic is wrong! expect: %x got: %x\n",
698 	LcpInfo.his_magic, magic);
699     /*
700      *  XXX: We should send terminate request. But poor implementation
701      *       may die as a result.
702      */
703   }
704   RecvEchoLqr(bp);
705   pfree(bp);
706 }
707 
708 void
709 FsmRecvDiscReq(fp, lhp, bp)
710 struct fsm *fp;
711 struct fsmheader *lhp;
712 struct mbuf *bp;
713 {
714   LogPrintf(LOG_LCP, "%s: RecvDiscReq\n", fp->name);
715   pfree(bp);
716 }
717 
718 void
719 FsmRecvIdent(fp, lhp, bp)
720 struct fsm *fp;
721 struct fsmheader *lhp;
722 struct mbuf *bp;
723 {
724   LogPrintf(LOG_LCP, "%s: RecvIdent\n", fp->name);
725   pfree(bp);
726 }
727 
728 void
729 FsmRecvTimeRemain(fp, lhp, bp)
730 struct fsm *fp;
731 struct fsmheader *lhp;
732 struct mbuf *bp;
733 {
734   LogPrintf(LOG_LCP, "%s: RecvTimeRemain\n", fp->name);
735   pfree(bp);
736 }
737 
738 void
739 FsmRecvResetReq(fp, lhp, bp)
740 struct fsm *fp;
741 struct fsmheader *lhp;
742 struct mbuf *bp;
743 {
744   LogPrintf(LOG_LCP, "%s: RecvResetReq\n", fp->name);
745   CcpRecvResetReq(fp);
746   LogPrintf(LOG_LCP, "%s: SendResetAck\n", fp->name);
747   FsmOutput(fp, CODE_RESETACK, fp->reqid, NULL, 0);
748   pfree(bp);
749 }
750 
751 void
752 FsmRecvResetAck(fp, lhp, bp)
753 struct fsm *fp;
754 struct fsmheader *lhp;
755 struct mbuf *bp;
756 {
757   LogPrintf(LOG_LCP, "%s: RecvResetAck\n", fp->name);
758   fp->reqid++;
759   pfree(bp);
760 }
761 
762 struct fsmcodedesc FsmCodes[] = {
763  { FsmRecvConfigReq,  "Configure Request", },
764  { FsmRecvConfigAck,  "Configure Ack", },
765  { FsmRecvConfigNak,  "Configure Nak", },
766  { FsmRecvConfigRej,  "Configure Reject", },
767  { FsmRecvTermReq,    "Terminate Request", },
768  { FsmRecvTermAck,    "Terminate Ack", },
769  { FsmRecvCodeRej,    "Code Reject", },
770  { FsmRecvProtoRej,   "Protocol Reject", },
771  { FsmRecvEchoReq,    "Echo Request", },
772  { FsmRecvEchoRep,    "Echo Reply", },
773  { FsmRecvDiscReq,    "Discard Request", },
774  { FsmRecvIdent,      "Ident", },
775  { FsmRecvTimeRemain, "Time Remain", },
776  { FsmRecvResetReq,   "Reset Request", },
777  { FsmRecvResetAck,   "Reset Ack", },
778 };
779 
780 void
781 FsmInput(fp, bp)
782 struct fsm *fp;
783 struct mbuf *bp;
784 {
785   int len;
786   struct fsmheader *lhp;
787   struct fsmcodedesc *codep;
788 
789   len = plength(bp);
790   if (len < sizeof(struct fsmheader)) {
791     pfree(bp);
792     return;
793   }
794   lhp = (struct fsmheader *)MBUF_CTOP(bp);
795   if (lhp->code == 0 || lhp->code > fp->max_code) {
796     pfree(bp);		/* XXX: Should send code reject */
797     return;
798   }
799 
800   bp->offset += sizeof(struct fsmheader);
801   bp->cnt -= sizeof(struct fsmheader);
802 
803   codep = FsmCodes + lhp->code - 1;
804   LogPrintf(LOG_LCP, "%s: Received %s (%d) state = %s (%d)\n",
805     fp->name, codep->name, lhp->id, StateNames[fp->state], fp->state);
806 #ifdef DEBUG
807   LogMemory();
808 #endif
809   (codep->action)(fp, lhp, bp);
810 #ifdef DEBUG
811   LogMemory();
812 #endif
813 }
814