xref: /freebsd/usr.sbin/ppp/fsm.c (revision 5ebc7e6281887681c3a348a5a4c902e262ccd656)
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.2 1995/02/26 12:17:27 amurai 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 
32 void FsmSendConfigReq(struct fsm *fp);
33 void FsmSendTerminateReq(struct fsm *fp);
34 void FsmInitRestartCounter(struct fsm *fp);
35 void FsmTimeout(struct fsm *fp);
36 
37 char *StateNames[] = {
38   "Initial", "Starting", "Closed", "Stopped", "Closing", "Stopping",
39   "Req-Sent", "Ack-Rcvd", "Ack-Sent", "Opend",
40 };
41 
42 void
43 FsmInit(fp)
44 struct 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 
55 void
56 NewState(fp, new)
57 struct fsm *fp;
58 int 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 
67 void
68 FsmOutput(fp, code, id, ptr, count)
69 struct fsm *fp;
70 u_int code, id;
71 u_char *ptr;
72 int 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 
92 void
93 FsmOpen(fp)
94 struct 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 
125 void
126 FsmUp(fp)
127 struct 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 
145 void
146 FsmDown(fp)
147 struct 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 
170 void
171 FsmClose(fp)
172 struct 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  */
200 void
201 FsmSendConfigReq(fp)
202 struct 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 
213 void
214 FsmSendTerminateReq(fp)
215 struct 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 
224 static void
225 FsmSendConfigAck(fp, lhp, option, count)
226 struct fsm *fp;
227 struct fsmheader *lhp;
228 u_char *option;
229 int 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 
236 static void
237 FsmSendConfigRej(fp, lhp, option, count)
238 struct fsm *fp;
239 struct fsmheader *lhp;
240 u_char *option;
241 int 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 
248 static void
249 FsmSendConfigNak(fp, lhp, option, count)
250 struct fsm *fp;
251 struct fsmheader *lhp;
252 u_char *option;
253 int 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  */
264 void
265 FsmTimeout(fp)
266 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 
304 void
305 FsmInitRestartCounter(fp)
306 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  */
318 void
319 FsmRecvConfigReq(fp, lhp, bp)			/* RCR */
320 struct fsm *fp;
321 struct fsmheader *lhp;
322 struct 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:
352 logprintf("## 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 
406 void
407 FsmRecvConfigAck(fp, lhp, bp)			/* RCA */
408 struct fsm *fp;
409 struct fsmheader *lhp;
410 struct 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 
442 void
443 FsmRecvConfigNak(fp, lhp, bp)			/* RCN */
444 struct fsm *fp;
445 struct fsmheader *lhp;
446 struct 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 
498 void
499 FsmRecvTermReq(fp, lhp, bp)				/* RTR */
500 struct fsm *fp;
501 struct fsmheader *lhp;
502 struct 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 
532 void
533 FsmRecvTermAck(fp, lhp, bp)			/* RTA */
534 struct fsm *fp;
535 struct fsmheader *lhp;
536 struct 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 
559 void
560 FsmRecvConfigRej(fp, lhp, bp)			/* RCJ */
561 struct fsm *fp;
562 struct fsmheader *lhp;
563 struct 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 
615 void
616 FsmRecvCodeRej(fp, lhp, bp)
617 struct fsm *fp;
618 struct fsmheader *lhp;
619 struct mbuf *bp;
620 {
621   LogPrintf(LOG_LCP, "%s: RecvCodeRej\n", fp->name);
622   pfree(bp);
623 }
624 
625 void
626 FsmRecvProtoRej(fp, lhp, bp)
627 struct fsm *fp;
628 struct fsmheader *lhp;
629 struct 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 
657 void
658 FsmRecvEchoReq(fp, lhp, bp)
659 struct fsm *fp;
660 struct fsmheader *lhp;
661 struct 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 
682 void
683 FsmRecvEchoRep(fp, lhp, bp)
684 struct fsm *fp;
685 struct fsmheader *lhp;
686 struct 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 
704 void
705 FsmRecvDiscReq(fp, lhp, bp)
706 struct fsm *fp;
707 struct fsmheader *lhp;
708 struct mbuf *bp;
709 {
710   LogPrintf(LOG_LCP, "%s: RecvDiscReq\n", fp->name);
711   pfree(bp);
712 }
713 
714 void
715 FsmRecvIdent(fp, lhp, bp)
716 struct fsm *fp;
717 struct fsmheader *lhp;
718 struct mbuf *bp;
719 {
720   LogPrintf(LOG_LCP, "%s: RecvIdent\n", fp->name);
721   pfree(bp);
722 }
723 
724 void
725 FsmRecvTimeRemain(fp, lhp, bp)
726 struct fsm *fp;
727 struct fsmheader *lhp;
728 struct mbuf *bp;
729 {
730   LogPrintf(LOG_LCP, "%s: RecvTimeRemain\n", fp->name);
731   pfree(bp);
732 }
733 
734 void
735 FsmRecvResetReq(fp, lhp, bp)
736 struct fsm *fp;
737 struct fsmheader *lhp;
738 struct 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 
747 void
748 FsmRecvResetAck(fp, lhp, bp)
749 struct fsm *fp;
750 struct fsmheader *lhp;
751 struct mbuf *bp;
752 {
753   LogPrintf(LOG_LCP, "%s: RecvResetAck\n", fp->name);
754   fp->reqid++;
755   pfree(bp);
756 }
757 
758 struct 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 
776 void
777 FsmInput(fp, bp)
778 struct fsm *fp;
779 struct 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