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