fsm.c revision 22997
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#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:
353logprintf("## 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    /* Zero Restart counter */
526    (fp->SendTerminateAck)(fp);
527    NewState(fp, ST_STOPPING);
528    break;
529  }
530  pfree(bp);
531}
532
533void
534FsmRecvTermAck(fp, lhp, bp)			/* RTA */
535struct fsm *fp;
536struct fsmheader *lhp;
537struct 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
560void
561FsmRecvConfigRej(fp, lhp, bp)			/* RCJ */
562struct fsm *fp;
563struct fsmheader *lhp;
564struct 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_BIT, "%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_BIT, "%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
616void
617FsmRecvCodeRej(fp, lhp, bp)
618struct fsm *fp;
619struct fsmheader *lhp;
620struct mbuf *bp;
621{
622  LogPrintf(LOG_LCP_BIT, "%s: RecvCodeRej\n", fp->name);
623  pfree(bp);
624}
625
626void
627FsmRecvProtoRej(fp, lhp, bp)
628struct fsm *fp;
629struct fsmheader *lhp;
630struct mbuf *bp;
631{
632  u_short *sp, proto;
633
634  sp = (u_short *)MBUF_CTOP(bp);
635  proto = ntohs(*sp);
636  LogPrintf(LOG_LCP_BIT, "-- 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
658void
659FsmRecvEchoReq(fp, lhp, bp)
660struct fsm *fp;
661struct fsmheader *lhp;
662struct 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_BIT, "%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
683void
684FsmRecvEchoRep(fp, lhp, bp)
685struct fsm *fp;
686struct fsmheader *lhp;
687struct 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
708void
709FsmRecvDiscReq(fp, lhp, bp)
710struct fsm *fp;
711struct fsmheader *lhp;
712struct mbuf *bp;
713{
714  LogPrintf(LOG_LCP_BIT, "%s: RecvDiscReq\n", fp->name);
715  pfree(bp);
716}
717
718void
719FsmRecvIdent(fp, lhp, bp)
720struct fsm *fp;
721struct fsmheader *lhp;
722struct mbuf *bp;
723{
724  LogPrintf(LOG_LCP_BIT, "%s: RecvIdent\n", fp->name);
725  pfree(bp);
726}
727
728void
729FsmRecvTimeRemain(fp, lhp, bp)
730struct fsm *fp;
731struct fsmheader *lhp;
732struct mbuf *bp;
733{
734  LogPrintf(LOG_LCP_BIT, "%s: RecvTimeRemain\n", fp->name);
735  pfree(bp);
736}
737
738void
739FsmRecvResetReq(fp, lhp, bp)
740struct fsm *fp;
741struct fsmheader *lhp;
742struct mbuf *bp;
743{
744  LogPrintf(LOG_LCP_BIT, "%s: RecvResetReq\n", fp->name);
745  CcpRecvResetReq(fp);
746  LogPrintf(LOG_LCP_BIT, "%s: SendResetAck\n", fp->name);
747  FsmOutput(fp, CODE_RESETACK, fp->reqid, NULL, 0);
748  pfree(bp);
749}
750
751void
752FsmRecvResetAck(fp, lhp, bp)
753struct fsm *fp;
754struct fsmheader *lhp;
755struct mbuf *bp;
756{
757  LogPrintf(LOG_LCP_BIT, "%s: RecvResetAck\n", fp->name);
758  fp->reqid++;
759  pfree(bp);
760}
761
762struct 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
780void
781FsmInput(fp, bp)
782struct fsm *fp;
783struct 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_BIT, "%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