xref: /freebsd/usr.sbin/ppp/fsm.c (revision 17ee9d00bc1ae1e598c38f25826f861e4bc6c3ce)
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 
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   FsmOutput(fp, CODE_CONFIGACK, lhp->id, option, count);
233 }
234 
235 static void
236 FsmSendConfigRej(fp, lhp, option, count)
237 struct fsm *fp;
238 struct fsmheader *lhp;
239 u_char *option;
240 int count;
241 {
242   LogPrintf(LOG_LCP, "%s:  SendConfigRej(%s)\n", fp->name, StateNames[fp->state]);
243   FsmOutput(fp, CODE_CONFIGREJ, lhp->id, option, count);
244 }
245 
246 static void
247 FsmSendConfigNak(fp, lhp, option, count)
248 struct fsm *fp;
249 struct fsmheader *lhp;
250 u_char *option;
251 int count;
252 {
253   LogPrintf(LOG_LCP, "%s:  SendConfigNak(%s)\n",
254 	    fp->name, StateNames[fp->state]);
255   FsmOutput(fp, CODE_CONFIGNAK, lhp->id, option, count);
256 }
257 
258 /*
259  *	Timeout actions
260  */
261 void
262 FsmTimeout(fp)
263 struct fsm *fp;
264 {
265   if (fp->restart) {
266     switch (fp->state) {
267     case ST_CLOSING:
268     case ST_STOPPING:
269       FsmSendTerminateReq(fp);
270       break;
271     case ST_REQSENT:
272     case ST_ACKSENT:
273       FsmSendConfigReq(fp);
274       break;
275     case ST_ACKRCVD:
276       FsmSendConfigReq(fp);
277       NewState(fp, ST_REQSENT);
278       break;
279     }
280     StartTimer(&fp->FsmTimer);
281   } else {
282     switch (fp->state) {
283     case ST_CLOSING:
284       NewState(fp, ST_CLOSED);
285       (fp->LayerFinish)(fp);
286       break;
287     case ST_STOPPING:
288       NewState(fp, ST_STOPPED);
289       (fp->LayerFinish)(fp);
290       break;
291     case ST_REQSENT:		/* XXX: 3p */
292     case ST_ACKSENT:
293     case ST_ACKRCVD:
294       NewState(fp, ST_STOPPED);
295       (fp->LayerFinish)(fp);
296       break;
297     }
298   }
299 }
300 
301 void
302 FsmInitRestartCounter(fp)
303 struct fsm *fp;
304 {
305   StopTimer(&fp->FsmTimer);
306   fp->FsmTimer.state = TIMER_STOPPED;
307   fp->FsmTimer.func = FsmTimeout;
308   fp->FsmTimer.arg = (void *)fp;
309   (fp->InitRestartCounter)(fp);
310 }
311 
312 /*
313  *   Actions when receive packets
314  */
315 void
316 FsmRecvConfigReq(fp, lhp, bp)			/* RCR */
317 struct fsm *fp;
318 struct fsmheader *lhp;
319 struct mbuf *bp;
320 {
321   int plen;
322   int ackaction = 0;
323 
324   plen = plength(bp);
325   if (plen < sizeof(struct fsmconfig)) {
326 logprintf("** plen = %d\n", plen);
327     pfree(bp);
328     return;
329   }
330 
331   /*
332    *  Check and process easy case
333    */
334   switch (fp->state) {
335   case ST_INITIAL:
336   case ST_STARTING:
337     LogPrintf(LOG_LCP, "%s: Oops, RCR in %s.\n",
338 	    fp->name, StateNames[fp->state]);
339     pfree(bp);
340     return;
341   case ST_CLOSED:
342     (fp->SendTerminateAck)(fp);
343     pfree(bp);
344     return;
345   case ST_CLOSING:
346   case ST_STOPPING:
347 logprintf("## state = %d\n", fp->state);
348     pfree(bp);
349     return;
350   }
351 
352   (fp->DecodeConfig)(bp, MODE_REQ);
353 
354   if (nakp == NakBuff && rejp == RejBuff)
355     ackaction = 1;
356 
357   switch (fp->state) {
358   case ST_OPENED:
359     (fp->LayerDown)(fp);
360     FsmSendConfigReq(fp);
361     break;
362   case ST_STOPPED:
363     FsmInitRestartCounter(fp);
364     FsmSendConfigReq(fp);
365     break;
366   }
367 
368   if (rejp != RejBuff)
369     FsmSendConfigRej(fp, lhp, RejBuff, rejp - RejBuff);
370   if (nakp != NakBuff)
371     FsmSendConfigNak(fp, lhp, NakBuff, nakp - NakBuff);
372   if (ackaction)
373     FsmSendConfigAck(fp, lhp, AckBuff, ackp - AckBuff);
374 
375   switch (fp->state) {
376   case ST_STOPPED:
377   case ST_OPENED:
378     if (ackaction)
379       NewState(fp, ST_ACKSENT);
380     else
381       NewState(fp, ST_REQSENT);
382     break;
383   case ST_REQSENT:
384     if (ackaction)
385       NewState(fp, ST_ACKSENT);
386     break;
387   case ST_ACKRCVD:
388     if (ackaction) {
389       NewState(fp, ST_OPENED);
390       (fp->LayerUp)(fp);
391     }
392     break;
393   case ST_ACKSENT:
394     if (!ackaction)
395       NewState(fp, ST_REQSENT);
396     break;
397   }
398   pfree(bp);
399 }
400 
401 void
402 FsmRecvConfigAck(fp, lhp, bp)			/* RCA */
403 struct fsm *fp;
404 struct fsmheader *lhp;
405 struct mbuf *bp;
406 {
407   switch (fp->state) {
408   case ST_CLOSED:
409   case ST_STOPPED:
410     (fp->SendTerminateAck)(fp);
411     break;
412   case ST_CLOSING:
413   case ST_STOPPING:
414     break;
415   case ST_REQSENT:
416     FsmInitRestartCounter(fp);
417     NewState(fp, ST_ACKRCVD);
418     break;
419   case ST_ACKRCVD:
420     FsmSendConfigReq(fp);
421     NewState(fp, ST_REQSENT);
422     break;
423   case ST_ACKSENT:
424     FsmInitRestartCounter(fp);
425     NewState(fp, ST_OPENED);
426     (fp->LayerUp)(fp);
427     break;
428   case ST_OPENED:
429     (fp->LayerDown)(fp);
430     FsmSendConfigReq(fp);
431     NewState(fp, ST_REQSENT);
432     break;
433   }
434   pfree(bp);
435 }
436 
437 void
438 FsmRecvConfigNak(fp, lhp, bp)			/* RCN */
439 struct fsm *fp;
440 struct fsmheader *lhp;
441 struct mbuf *bp;
442 {
443   int plen;
444 
445   plen = plength(bp);
446   if (plen < sizeof(struct fsmconfig)) {
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(LOG_LCP, "%s: Oops, RCN in %s.\n",
458 	    fp->name, StateNames[fp->state]);
459     pfree(bp);
460     return;
461   case ST_CLOSED:
462   case ST_STOPPED:
463     (fp->SendTerminateAck)(fp);
464     pfree(bp);
465     return;
466   case ST_CLOSING:
467   case ST_STOPPING:
468     pfree(bp);
469     return;
470   }
471 
472   (fp->DecodeConfig)(bp, MODE_NAK);
473 
474   switch (fp->state) {
475   case ST_REQSENT:
476   case ST_ACKSENT:
477     FsmInitRestartCounter(fp);
478     FsmSendConfigReq(fp);
479     break;
480   case ST_OPENED:
481     (fp->LayerDown)(fp);
482     /* Fall down */
483   case ST_ACKRCVD:
484     FsmSendConfigReq(fp);
485     NewState(fp, ST_REQSENT);
486     break;
487   }
488 
489   pfree(bp);
490 }
491 
492 void
493 FsmRecvTermReq(fp, lhp, bp)				/* RTR */
494 struct fsm *fp;
495 struct fsmheader *lhp;
496 struct mbuf *bp;
497 {
498   switch (fp->state) {
499   case ST_INITIAL:
500   case ST_STARTING:
501     LogPrintf(LOG_LCP, "%s: Oops, RTR in %s\n", fp->name,
502 	    StateNames[fp->state]);
503     break;
504   case ST_CLOSED:
505   case ST_STOPPED:
506   case ST_CLOSING:
507   case ST_STOPPING:
508   case ST_REQSENT:
509     (fp->SendTerminateAck)(fp);
510     break;
511   case ST_ACKRCVD:
512   case ST_ACKSENT:
513     (fp->SendTerminateAck)(fp);
514     NewState(fp, ST_REQSENT);
515     break;
516   case ST_OPENED:
517     (fp->LayerDown)(fp);
518     /* Zero Restart counter */
519     (fp->SendTerminateAck)(fp);
520     NewState(fp, ST_STOPPING);
521     break;
522   }
523   pfree(bp);
524 }
525 
526 void
527 FsmRecvTermAck(fp, lhp, bp)			/* RTA */
528 struct fsm *fp;
529 struct fsmheader *lhp;
530 struct mbuf *bp;
531 {
532   switch (fp->state) {
533   case ST_CLOSING:
534     NewState(fp, ST_CLOSED);
535     (fp->LayerFinish)(fp);
536     break;
537   case ST_STOPPING:
538     NewState(fp, ST_STOPPED);
539     (fp->LayerFinish)(fp);
540     break;
541   case ST_ACKRCVD:
542     NewState(fp, ST_REQSENT);
543     break;
544   case ST_OPENED:
545     (fp->LayerDown)(fp);
546     FsmSendConfigReq(fp);
547     NewState(fp, ST_REQSENT);
548     break;
549   }
550   pfree(bp);
551 }
552 
553 void
554 FsmRecvConfigRej(fp, lhp, bp)			/* RCJ */
555 struct fsm *fp;
556 struct fsmheader *lhp;
557 struct mbuf *bp;
558 {
559   int plen;
560 
561   plen = plength(bp);
562   if (plen < sizeof(struct fsmconfig)) {
563     pfree(bp);
564     return;
565   }
566   LogPrintf(LOG_LCP, "%s: RecvConfigRej.\n", fp->name);
567 
568   /*
569    *  Check and process easy case
570    */
571   switch (fp->state) {
572   case ST_INITIAL:
573   case ST_STARTING:
574     LogPrintf(LOG_LCP, "%s: Oops, RCJ in %s.\n",
575 	    fp->name, StateNames[fp->state]);
576     pfree(bp);
577     return;
578   case ST_CLOSED:
579   case ST_STOPPED:
580     (fp->SendTerminateAck)(fp);
581     pfree(bp);
582     return;
583   case ST_CLOSING:
584   case ST_STOPPING:
585     pfree(bp);
586     return;
587   }
588 
589   (fp->DecodeConfig)(bp, MODE_REJ);
590 
591   switch (fp->state) {
592   case ST_REQSENT:
593   case ST_ACKSENT:
594     FsmInitRestartCounter(fp);
595     FsmSendConfigReq(fp);
596     break;
597   case ST_OPENED:
598     (fp->LayerDown)(fp);
599     /* Fall down */
600   case ST_ACKRCVD:
601     FsmSendConfigReq(fp);
602     NewState(fp, ST_REQSENT);
603     break;
604   }
605   pfree(bp);
606 }
607 
608 void
609 FsmRecvCodeRej(fp, lhp, bp)
610 struct fsm *fp;
611 struct fsmheader *lhp;
612 struct mbuf *bp;
613 {
614   LogPrintf(LOG_LCP, "%s: RecvCodeRej\n", fp->name);
615   pfree(bp);
616 }
617 
618 void
619 FsmRecvProtoRej(fp, lhp, bp)
620 struct fsm *fp;
621 struct fsmheader *lhp;
622 struct mbuf *bp;
623 {
624   u_short *sp, proto;
625 
626   sp = (u_short *)MBUF_CTOP(bp);
627   proto = ntohs(*sp);
628   LogPrintf(LOG_LCP, "-- Protocol (%04x) was rejected.\n", proto);
629 
630   switch (proto) {
631   case PROTO_LQR:
632     StopLqr(LQM_LQR);
633     break;
634   case PROTO_CCP:
635     fp = &CcpFsm;
636     (fp->LayerFinish)(fp);
637     switch (fp->state) {
638     case ST_CLOSED:
639     case ST_CLOSING:
640       NewState(fp, ST_CLOSED);
641     default:
642       NewState(fp, ST_STOPPED);
643       break;
644     }
645     break;
646   }
647   pfree(bp);
648 }
649 
650 void
651 FsmRecvEchoReq(fp, lhp, bp)
652 struct fsm *fp;
653 struct fsmheader *lhp;
654 struct mbuf *bp;
655 {
656   u_char *cp;
657   u_long *lp, magic;
658 
659   cp = MBUF_CTOP(bp);
660   lp = (u_long *)cp;
661   magic = ntohl(*lp);
662   if (magic != LcpInfo.his_magic) {
663     logprintf("RecvEchoReq: his magic is bad!!\n");
664     /* XXX: We should send terminate request */
665   }
666 
667   if (fp->state == ST_OPENED) {
668     *lp = htonl(LcpInfo.want_magic);	/* Insert local magic number */
669     LogPrintf(LOG_LCP, "%s:  SendEchoRep(%s)\n", fp->name, StateNames[fp->state]);
670     FsmOutput(fp, CODE_ECHOREP, lhp->id, cp, plength(bp));
671   }
672   pfree(bp);
673 }
674 
675 void
676 FsmRecvEchoRep(fp, lhp, bp)
677 struct fsm *fp;
678 struct fsmheader *lhp;
679 struct mbuf *bp;
680 {
681   u_long *lp, magic;
682 
683   lp = (u_long *)MBUF_CTOP(bp);
684   magic = ntohl(*lp);
685   if (magic != 0 && magic != LcpInfo.his_magic) {
686     logprintf("RecvEchoRep: his magic is wrong! expect: %x got: %x\n",
687 	LcpInfo.his_magic, magic);
688     /*
689      *  XXX: We should send terminate request. But poor implementation
690      *       may die as a result.
691      */
692   }
693   RecvEchoLqr(bp);
694   pfree(bp);
695 }
696 
697 void
698 FsmRecvDiscReq(fp, lhp, bp)
699 struct fsm *fp;
700 struct fsmheader *lhp;
701 struct mbuf *bp;
702 {
703   LogPrintf(LOG_LCP, "%s: RecvDiscReq\n", fp->name);
704   pfree(bp);
705 }
706 
707 void
708 FsmRecvIdent(fp, lhp, bp)
709 struct fsm *fp;
710 struct fsmheader *lhp;
711 struct mbuf *bp;
712 {
713   LogPrintf(LOG_LCP, "%s: RecvIdent\n", fp->name);
714   pfree(bp);
715 }
716 
717 void
718 FsmRecvTimeRemain(fp, lhp, bp)
719 struct fsm *fp;
720 struct fsmheader *lhp;
721 struct mbuf *bp;
722 {
723   LogPrintf(LOG_LCP, "%s: RecvTimeRemain\n", fp->name);
724   pfree(bp);
725 }
726 
727 void
728 FsmRecvResetReq(fp, lhp, bp)
729 struct fsm *fp;
730 struct fsmheader *lhp;
731 struct mbuf *bp;
732 {
733   LogPrintf(LOG_LCP, "%s: RecvResetReq\n", fp->name);
734   CcpRecvResetReq(fp);
735   LogPrintf(LOG_LCP, "%s: SendResetAck\n", fp->name);
736   FsmOutput(fp, CODE_RESETACK, fp->reqid, NULL, 0);
737   pfree(bp);
738 }
739 
740 void
741 FsmRecvResetAck(fp, lhp, bp)
742 struct fsm *fp;
743 struct fsmheader *lhp;
744 struct mbuf *bp;
745 {
746   LogPrintf(LOG_LCP, "%s: RecvResetAck\n", fp->name);
747   fp->reqid++;
748   pfree(bp);
749 }
750 
751 struct fsmcodedesc FsmCodes[] = {
752  { FsmRecvConfigReq,  "Configure Request", },
753  { FsmRecvConfigAck,  "Configure Ack", },
754  { FsmRecvConfigNak,  "Configure Nak", },
755  { FsmRecvConfigRej,  "Configure Reject", },
756  { FsmRecvTermReq,    "Terminate Request", },
757  { FsmRecvTermAck,    "Terminate Ack", },
758  { FsmRecvCodeRej,    "Code Reject", },
759  { FsmRecvProtoRej,   "Protocol Reject", },
760  { FsmRecvEchoReq,    "Echo Request", },
761  { FsmRecvEchoRep,    "Echo Reply", },
762  { FsmRecvDiscReq,    "Discard Request", },
763  { FsmRecvIdent,      "Ident", },
764  { FsmRecvTimeRemain, "Time Remain", },
765  { FsmRecvResetReq,   "Reset Request", },
766  { FsmRecvResetAck,   "Reset Ack", },
767 };
768 
769 void
770 FsmInput(fp, bp)
771 struct fsm *fp;
772 struct mbuf *bp;
773 {
774   int len;
775   struct fsmheader *lhp;
776   struct fsmcodedesc *codep;
777 
778   len = plength(bp);
779   if (len < sizeof(struct fsmheader)) {
780     pfree(bp);
781     return;
782   }
783   lhp = (struct fsmheader *)MBUF_CTOP(bp);
784   if (lhp->code == 0 || lhp->code > fp->max_code) {
785     pfree(bp);		/* XXX: Should send code reject */
786     return;
787   }
788 
789   bp->offset += sizeof(struct fsmheader);
790   bp->cnt -= sizeof(struct fsmheader);
791 
792   codep = FsmCodes + lhp->code - 1;
793   LogPrintf(LOG_LCP, "%s: Received %s (%d) state = %s (%d)\n",
794     fp->name, codep->name, lhp->code, StateNames[fp->state], fp->state);
795 #ifdef DEBUG
796   LogMemory();
797 #endif
798   (codep->action)(fp, lhp, bp);
799 #ifdef DEBUG
800   LogMemory();
801 #endif
802 }
803