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