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