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