fsm.c revision 37320
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.34 1998/06/27 23:48:43 brian Exp $
21 *
22 *  TODO:
23 */
24
25#include <sys/types.h>
26#include <netinet/in.h>
27#include <netinet/in_systm.h>
28#include <netinet/ip.h>
29#include <sys/un.h>
30
31#include <string.h>
32#include <termios.h>
33
34#include "mbuf.h"
35#include "log.h"
36#include "defs.h"
37#include "timer.h"
38#include "fsm.h"
39#include "iplist.h"
40#include "lqr.h"
41#include "hdlc.h"
42#include "throughput.h"
43#include "slcompress.h"
44#include "ipcp.h"
45#include "filter.h"
46#include "descriptor.h"
47#include "lcp.h"
48#include "ccp.h"
49#include "link.h"
50#include "mp.h"
51#include "bundle.h"
52#include "async.h"
53#include "physical.h"
54#include "lcpproto.h"
55
56static void FsmSendConfigReq(struct fsm *);
57static void FsmSendTerminateReq(struct fsm *);
58static void FsmInitRestartCounter(struct fsm *);
59
60typedef void (recvfn)(struct fsm *, struct fsmheader *, struct mbuf *);
61static recvfn FsmRecvConfigReq, FsmRecvConfigAck, FsmRecvConfigNak,
62              FsmRecvConfigRej, FsmRecvTermReq, FsmRecvTermAck,
63              FsmRecvCodeRej, FsmRecvProtoRej, FsmRecvEchoReq,
64              FsmRecvEchoRep, FsmRecvDiscReq, FsmRecvIdent,
65              FsmRecvTimeRemain, FsmRecvResetReq, FsmRecvResetAck;
66
67static const struct fsmcodedesc {
68  recvfn *recv;
69  unsigned check_reqid : 1;
70  unsigned inc_reqid : 1;
71  const char *name;
72} FsmCodes[] = {
73  { FsmRecvConfigReq, 0, 0, "ConfigReq"    },
74  { FsmRecvConfigAck, 1, 1, "ConfigAck"    },
75  { FsmRecvConfigNak, 1, 1, "ConfigNak"    },
76  { FsmRecvConfigRej, 1, 1, "ConfigRej"    },
77  { FsmRecvTermReq,   0, 0, "TerminateReq" },
78  { FsmRecvTermAck,   1, 1, "TerminateAck" },
79  { FsmRecvCodeRej,   0, 0, "CodeRej"      },
80  { FsmRecvProtoRej,  0, 0, "ProtocolRej"  },
81  { FsmRecvEchoReq,   0, 0, "EchoRequest"  },
82  { FsmRecvEchoRep,   0, 0, "EchoReply"    },
83  { FsmRecvDiscReq,   0, 0, "DiscardReq"   },
84  { FsmRecvIdent,     0, 0, "Ident"        },
85  { FsmRecvTimeRemain,0, 0, "TimeRemain"   },
86  { FsmRecvResetReq,  0, 0, "ResetReqt"    },
87  { FsmRecvResetAck,  0, 1, "ResetAck"     }
88};
89
90static const char *
91Code2Nam(u_int code)
92{
93  if (code == 0 || code > sizeof FsmCodes / sizeof FsmCodes[0])
94    return "Unknown";
95  return FsmCodes[code-1].name;
96}
97
98const char *
99State2Nam(u_int state)
100{
101  static const char *StateNames[] = {
102    "Initial", "Starting", "Closed", "Stopped", "Closing", "Stopping",
103    "Req-Sent", "Ack-Rcvd", "Ack-Sent", "Opened",
104  };
105
106  if (state >= sizeof StateNames / sizeof StateNames[0])
107    return "unknown";
108  return StateNames[state];
109}
110
111static void
112StoppedTimeout(void *v)
113{
114  struct fsm *fp = (struct fsm *)v;
115
116  log_Printf(fp->LogLevel, "%s: Stopped timer expired\n", fp->link->name);
117  if (fp->OpenTimer.state == TIMER_RUNNING) {
118    log_Printf(LogWARN, "%s: %s: aborting open delay due to stopped timer\n",
119              fp->link->name, fp->name);
120    timer_Stop(&fp->OpenTimer);
121  }
122  if (fp->state == ST_STOPPED)
123    fsm2initial(fp);
124}
125
126void
127fsm_Init(struct fsm *fp, const char *name, u_short proto, int mincode,
128         int maxcode, int maxcfg, int LogLevel, struct bundle *bundle,
129         struct link *l, const struct fsm_parent *parent,
130         struct fsm_callbacks *fn, const char *timer_names[3])
131{
132  fp->name = name;
133  fp->proto = proto;
134  fp->min_code = mincode;
135  fp->max_code = maxcode;
136  fp->state = fp->min_code > CODE_TERMACK ? ST_OPENED : ST_INITIAL;
137  fp->reqid = 1;
138  fp->restart = 1;
139  fp->maxconfig = maxcfg;
140  memset(&fp->FsmTimer, '\0', sizeof fp->FsmTimer);
141  memset(&fp->OpenTimer, '\0', sizeof fp->OpenTimer);
142  memset(&fp->StoppedTimer, '\0', sizeof fp->StoppedTimer);
143  fp->LogLevel = LogLevel;
144  fp->link = l;
145  fp->bundle = bundle;
146  fp->parent = parent;
147  fp->fn = fn;
148  fp->FsmTimer.name = timer_names[0];
149  fp->OpenTimer.name = timer_names[1];
150  fp->StoppedTimer.name = timer_names[2];
151}
152
153static void
154NewState(struct fsm * fp, int new)
155{
156  log_Printf(fp->LogLevel, "%s: State change %s --> %s\n",
157	    fp->link->name, State2Nam(fp->state), State2Nam(new));
158  if (fp->state == ST_STOPPED && fp->StoppedTimer.state == TIMER_RUNNING)
159    timer_Stop(&fp->StoppedTimer);
160  fp->state = new;
161  if ((new >= ST_INITIAL && new <= ST_STOPPED) || (new == ST_OPENED)) {
162    timer_Stop(&fp->FsmTimer);
163    if (new == ST_STOPPED && fp->StoppedTimer.load) {
164      timer_Stop(&fp->StoppedTimer);
165      fp->StoppedTimer.func = StoppedTimeout;
166      fp->StoppedTimer.arg = (void *) fp;
167      timer_Start(&fp->StoppedTimer);
168    }
169  }
170}
171
172void
173fsm_Output(struct fsm *fp, u_int code, u_int id, u_char *ptr, int count)
174{
175  int plen;
176  struct fsmheader lh;
177  struct mbuf *bp;
178
179  if (log_IsKept(fp->LogLevel)) {
180    log_Printf(fp->LogLevel, "%s: Send%s(%d) state = %s\n",
181              fp->link->name, Code2Nam(code), id, State2Nam(fp->state));
182    switch (code) {
183      case CODE_CONFIGREQ:
184      case CODE_CONFIGACK:
185      case CODE_CONFIGREJ:
186      case CODE_CONFIGNAK:
187        (*fp->fn->DecodeConfig)(fp, ptr, count, MODE_NOP, NULL);
188        if (count < sizeof(struct fsmconfig))
189          log_Printf(fp->LogLevel, "  [EMPTY]\n");
190        break;
191    }
192  }
193
194  plen = sizeof(struct fsmheader) + count;
195  lh.code = code;
196  lh.id = id;
197  lh.length = htons(plen);
198  bp = mbuf_Alloc(plen, MB_FSM);
199  memcpy(MBUF_CTOP(bp), &lh, sizeof(struct fsmheader));
200  if (count)
201    memcpy(MBUF_CTOP(bp) + sizeof(struct fsmheader), ptr, count);
202  log_DumpBp(LogDEBUG, "fsm_Output", bp);
203  hdlc_Output(fp->link, PRI_LINK, fp->proto, bp);
204}
205
206static void
207FsmOpenNow(void *v)
208{
209  struct fsm *fp = (struct fsm *)v;
210
211  timer_Stop(&fp->OpenTimer);
212  if (fp->state <= ST_STOPPED) {
213    if (fp->state != ST_STARTING) {
214      /*
215       * In practice, we're only here in ST_STOPPED (when delaying the
216       * first config request) or ST_CLOSED (when openmode == 0).
217       *
218       * The ST_STOPPED bit is breaking the RFC already :-(
219       *
220       * According to the RFC (1661) state transition table, a TLS isn't
221       * required for an Open event when state == Closed, but the RFC
222       * must be wrong as TLS hasn't yet been called (since the last TLF)
223       * ie, Initial gets an `Up' event, Closing gets a RTA etc.
224       */
225      (*fp->fn->LayerStart)(fp);
226      (*fp->parent->LayerStart)(fp->parent->object, fp);
227    }
228    FsmInitRestartCounter(fp);
229    FsmSendConfigReq(fp);
230    NewState(fp, ST_REQSENT);
231  }
232}
233
234void
235fsm_Open(struct fsm * fp)
236{
237  switch (fp->state) {
238  case ST_INITIAL:
239    NewState(fp, ST_STARTING);
240    (*fp->fn->LayerStart)(fp);
241    (*fp->parent->LayerStart)(fp->parent->object, fp);
242    break;
243  case ST_CLOSED:
244    if (fp->open_mode == OPEN_PASSIVE) {
245      NewState(fp, ST_STOPPED);		/* XXX: This is a hack ! */
246    } else if (fp->open_mode > 0) {
247      if (fp->open_mode > 1)
248        log_Printf(LogPHASE, "%s: Entering STOPPED state for %d seconds\n",
249                  fp->link->name, fp->open_mode);
250      NewState(fp, ST_STOPPED);		/* XXX: This is a not-so-bad hack ! */
251      timer_Stop(&fp->OpenTimer);
252      fp->OpenTimer.load = fp->open_mode * SECTICKS;
253      fp->OpenTimer.func = FsmOpenNow;
254      fp->OpenTimer.arg = (void *)fp;
255      timer_Start(&fp->OpenTimer);
256    } else
257      FsmOpenNow(fp);
258    break;
259  case ST_STOPPED:		/* XXX: restart option */
260  case ST_REQSENT:
261  case ST_ACKRCVD:
262  case ST_ACKSENT:
263  case ST_OPENED:		/* XXX: restart option */
264    break;
265  case ST_CLOSING:		/* XXX: restart option */
266  case ST_STOPPING:		/* XXX: restart option */
267    NewState(fp, ST_STOPPING);
268    break;
269  }
270}
271
272void
273fsm_Up(struct fsm * fp)
274{
275  switch (fp->state) {
276  case ST_INITIAL:
277    log_Printf(fp->LogLevel, "FSM: Using \"%s\" as a transport\n",
278              fp->link->name);
279    NewState(fp, ST_CLOSED);
280    break;
281  case ST_STARTING:
282    FsmInitRestartCounter(fp);
283    FsmSendConfigReq(fp);
284    NewState(fp, ST_REQSENT);
285    break;
286  default:
287    log_Printf(fp->LogLevel, "%s: Oops, Up at %s\n",
288              fp->link->name, State2Nam(fp->state));
289    break;
290  }
291}
292
293void
294fsm_Down(struct fsm *fp)
295{
296  switch (fp->state) {
297  case ST_CLOSED:
298    NewState(fp, ST_INITIAL);
299    break;
300  case ST_CLOSING:
301    (*fp->fn->LayerFinish)(fp);
302    NewState(fp, ST_INITIAL);
303    (*fp->parent->LayerFinish)(fp->parent->object, fp);
304    break;
305  case ST_STOPPED:
306    NewState(fp, ST_STARTING);
307    (*fp->fn->LayerStart)(fp);
308    (*fp->parent->LayerStart)(fp->parent->object, fp);
309    break;
310  case ST_STOPPING:
311  case ST_REQSENT:
312  case ST_ACKRCVD:
313  case ST_ACKSENT:
314    NewState(fp, ST_STARTING);
315    break;
316  case ST_OPENED:
317    (*fp->fn->LayerDown)(fp);
318    NewState(fp, ST_STARTING);
319    (*fp->parent->LayerDown)(fp->parent->object, fp);
320    break;
321  }
322}
323
324void
325fsm_Close(struct fsm *fp)
326{
327  switch (fp->state) {
328  case ST_STARTING:
329    (*fp->fn->LayerFinish)(fp);
330    NewState(fp, ST_INITIAL);
331    (*fp->parent->LayerFinish)(fp->parent->object, fp);
332    break;
333  case ST_STOPPED:
334    NewState(fp, ST_CLOSED);
335    break;
336  case ST_STOPPING:
337    NewState(fp, ST_CLOSING);
338    break;
339  case ST_OPENED:
340    (*fp->fn->LayerDown)(fp);
341    FsmInitRestartCounter(fp);
342    FsmSendTerminateReq(fp);
343    NewState(fp, ST_CLOSING);
344    (*fp->parent->LayerDown)(fp->parent->object, fp);
345    break;
346  case ST_REQSENT:
347  case ST_ACKRCVD:
348  case ST_ACKSENT:
349    FsmInitRestartCounter(fp);
350    FsmSendTerminateReq(fp);
351    NewState(fp, ST_CLOSING);
352    break;
353  }
354}
355
356/*
357 *	Send functions
358 */
359static void
360FsmSendConfigReq(struct fsm * fp)
361{
362  if (--fp->maxconfig > 0) {
363    (*fp->fn->SendConfigReq)(fp);
364    timer_Start(&fp->FsmTimer);	/* Start restart timer */
365    fp->restart--;		/* Decrement restart counter */
366  } else {
367    fsm_Close(fp);
368  }
369}
370
371static void
372FsmSendTerminateReq(struct fsm *fp)
373{
374  fsm_Output(fp, CODE_TERMREQ, fp->reqid, NULL, 0);
375  (*fp->fn->SentTerminateReq)(fp);
376  timer_Start(&fp->FsmTimer);	/* Start restart timer */
377  fp->restart--;		/* Decrement restart counter */
378}
379
380/*
381 *	Timeout actions
382 */
383static void
384FsmTimeout(void *v)
385{
386  struct fsm *fp = (struct fsm *)v;
387
388  if (fp->restart) {
389    switch (fp->state) {
390    case ST_CLOSING:
391    case ST_STOPPING:
392      FsmSendTerminateReq(fp);
393      break;
394    case ST_REQSENT:
395    case ST_ACKSENT:
396      FsmSendConfigReq(fp);
397      break;
398    case ST_ACKRCVD:
399      FsmSendConfigReq(fp);
400      NewState(fp, ST_REQSENT);
401      break;
402    }
403    timer_Start(&fp->FsmTimer);
404  } else {
405    switch (fp->state) {
406    case ST_CLOSING:
407      (*fp->fn->LayerFinish)(fp);
408      NewState(fp, ST_CLOSED);
409      (*fp->parent->LayerFinish)(fp->parent->object, fp);
410      break;
411    case ST_STOPPING:
412      (*fp->fn->LayerFinish)(fp);
413      NewState(fp, ST_STOPPED);
414      (*fp->parent->LayerFinish)(fp->parent->object, fp);
415      break;
416    case ST_REQSENT:		/* XXX: 3p */
417    case ST_ACKSENT:
418    case ST_ACKRCVD:
419      (*fp->fn->LayerFinish)(fp);
420      NewState(fp, ST_STOPPED);
421      (*fp->parent->LayerFinish)(fp->parent->object, fp);
422      break;
423    }
424  }
425}
426
427static void
428FsmInitRestartCounter(struct fsm * fp)
429{
430  timer_Stop(&fp->FsmTimer);
431  fp->FsmTimer.func = FsmTimeout;
432  fp->FsmTimer.arg = (void *) fp;
433  (*fp->fn->InitRestartCounter)(fp);
434}
435
436/*
437 *   Actions when receive packets
438 */
439static void
440FsmRecvConfigReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp)
441/* RCR */
442{
443  struct fsm_decode dec;
444  int plen, flen;
445  int ackaction = 0;
446
447  plen = mbuf_Length(bp);
448  flen = ntohs(lhp->length) - sizeof *lhp;
449  if (plen < flen) {
450    log_Printf(LogWARN, "%s: FsmRecvConfigReq: plen (%d) < flen (%d)\n",
451	      fp->link->name, plen, flen);
452    mbuf_Free(bp);
453    return;
454  }
455
456  /*
457   * Check and process easy case
458   */
459  switch (fp->state) {
460  case ST_INITIAL:
461    if (fp->proto == PROTO_CCP && fp->link->lcp.fsm.state == ST_OPENED) {
462      /*
463       * ccp_SetOpenMode() leaves us in initial if we're disabling
464       * & denying everything.  This is a bit smelly, we know that
465       * ``bp'' really has ``fsmheader'' in front of it, and CCP_PROTO
466       * in front of that.  CCP_PROTO isn't compressed either 'cos it
467       * doesn't begin with 0x00....
468       */
469      bp->offset -= sizeof(struct fsmheader) + 2;
470      bp->cnt += sizeof(struct fsmheader) + 2;
471      lcp_SendProtoRej(&fp->link->lcp, MBUF_CTOP(bp), bp->cnt);
472      mbuf_Free(bp);
473      return;
474    }
475    /* Drop through */
476  case ST_STARTING:
477    log_Printf(fp->LogLevel, "%s: Oops, RCR in %s.\n",
478              fp->link->name, State2Nam(fp->state));
479    mbuf_Free(bp);
480    return;
481  case ST_CLOSED:
482    (*fp->fn->SendTerminateAck)(fp, lhp->id);
483    mbuf_Free(bp);
484    return;
485  case ST_CLOSING:
486    log_Printf(fp->LogLevel, "%s: Error: Got ConfigReq while state = %s\n",
487              fp->link->name, State2Nam(fp->state));
488  case ST_STOPPING:
489    mbuf_Free(bp);
490    return;
491  }
492
493  dec.ackend = dec.ack;
494  dec.nakend = dec.nak;
495  dec.rejend = dec.rej;
496  (*fp->fn->DecodeConfig)(fp, MBUF_CTOP(bp), flen, MODE_REQ, &dec);
497  if (flen < sizeof(struct fsmconfig))
498    log_Printf(fp->LogLevel, "  [EMPTY]\n");
499
500  if (dec.nakend == dec.nak && dec.rejend == dec.rej)
501    ackaction = 1;
502
503  switch (fp->state) {
504  case ST_OPENED:
505    (*fp->fn->LayerDown)(fp);
506    FsmSendConfigReq(fp);
507    (*fp->parent->LayerDown)(fp->parent->object, fp);
508    break;
509  case ST_STOPPED:
510    FsmInitRestartCounter(fp);
511    FsmSendConfigReq(fp);
512    break;
513  }
514
515  if (dec.rejend != dec.rej)
516    fsm_Output(fp, CODE_CONFIGREJ, lhp->id, dec.rej, dec.rejend - dec.rej);
517  if (dec.nakend != dec.nak)
518    fsm_Output(fp, CODE_CONFIGNAK, lhp->id, dec.nak, dec.nakend - dec.nak);
519  if (ackaction)
520    fsm_Output(fp, CODE_CONFIGACK, lhp->id, dec.ack, dec.ackend - dec.ack);
521
522  switch (fp->state) {
523  case ST_OPENED:
524  case ST_STOPPED:
525    if (ackaction)
526      NewState(fp, ST_ACKSENT);
527    else
528      NewState(fp, ST_REQSENT);
529    break;
530  case ST_REQSENT:
531    if (ackaction)
532      NewState(fp, ST_ACKSENT);
533    break;
534  case ST_ACKRCVD:
535    if (ackaction) {
536      NewState(fp, ST_OPENED);
537      if ((*fp->fn->LayerUp)(fp))
538        (*fp->parent->LayerUp)(fp->parent->object, fp);
539      else {
540        (*fp->fn->LayerDown)(fp);
541        FsmInitRestartCounter(fp);
542        FsmSendTerminateReq(fp);
543        NewState(fp, ST_CLOSING);
544      }
545    }
546    break;
547  case ST_ACKSENT:
548    if (!ackaction)
549      NewState(fp, ST_REQSENT);
550    break;
551  }
552  mbuf_Free(bp);
553}
554
555static void
556FsmRecvConfigAck(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp)
557/* RCA */
558{
559  switch (fp->state) {
560    case ST_CLOSED:
561    case ST_STOPPED:
562    (*fp->fn->SendTerminateAck)(fp, lhp->id);
563    break;
564  case ST_CLOSING:
565  case ST_STOPPING:
566    break;
567  case ST_REQSENT:
568    FsmInitRestartCounter(fp);
569    NewState(fp, ST_ACKRCVD);
570    break;
571  case ST_ACKRCVD:
572    FsmSendConfigReq(fp);
573    NewState(fp, ST_REQSENT);
574    break;
575  case ST_ACKSENT:
576    FsmInitRestartCounter(fp);
577    NewState(fp, ST_OPENED);
578    if ((*fp->fn->LayerUp)(fp))
579      (*fp->parent->LayerUp)(fp->parent->object, fp);
580    else {
581      (*fp->fn->LayerDown)(fp);
582      FsmInitRestartCounter(fp);
583      FsmSendTerminateReq(fp);
584      NewState(fp, ST_CLOSING);
585    }
586    break;
587  case ST_OPENED:
588    (*fp->fn->LayerDown)(fp);
589    FsmSendConfigReq(fp);
590    NewState(fp, ST_REQSENT);
591    (*fp->parent->LayerDown)(fp->parent->object, fp);
592    break;
593  }
594  mbuf_Free(bp);
595}
596
597static void
598FsmRecvConfigNak(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp)
599/* RCN */
600{
601  struct fsm_decode dec;
602  int plen, flen;
603
604  plen = mbuf_Length(bp);
605  flen = ntohs(lhp->length) - sizeof *lhp;
606  if (plen < flen) {
607    mbuf_Free(bp);
608    return;
609  }
610
611  /*
612   * Check and process easy case
613   */
614  switch (fp->state) {
615  case ST_INITIAL:
616  case ST_STARTING:
617    log_Printf(fp->LogLevel, "%s: Oops, RCN in %s.\n",
618              fp->link->name, State2Nam(fp->state));
619    mbuf_Free(bp);
620    return;
621  case ST_CLOSED:
622  case ST_STOPPED:
623    (*fp->fn->SendTerminateAck)(fp, lhp->id);
624    mbuf_Free(bp);
625    return;
626  case ST_CLOSING:
627  case ST_STOPPING:
628    mbuf_Free(bp);
629    return;
630  }
631
632  dec.ackend = dec.ack;
633  dec.nakend = dec.nak;
634  dec.rejend = dec.rej;
635  (*fp->fn->DecodeConfig)(fp, MBUF_CTOP(bp), flen, MODE_NAK, &dec);
636  if (flen < sizeof(struct fsmconfig))
637    log_Printf(fp->LogLevel, "  [EMPTY]\n");
638
639  switch (fp->state) {
640  case ST_REQSENT:
641  case ST_ACKSENT:
642    FsmInitRestartCounter(fp);
643    FsmSendConfigReq(fp);
644    break;
645  case ST_OPENED:
646    (*fp->fn->LayerDown)(fp);
647    FsmSendConfigReq(fp);
648    NewState(fp, ST_REQSENT);
649    (*fp->parent->LayerDown)(fp->parent->object, fp);
650    break;
651  case ST_ACKRCVD:
652    FsmSendConfigReq(fp);
653    NewState(fp, ST_REQSENT);
654    break;
655  }
656
657  mbuf_Free(bp);
658}
659
660static void
661FsmRecvTermReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp)
662/* RTR */
663{
664  switch (fp->state) {
665  case ST_INITIAL:
666  case ST_STARTING:
667    log_Printf(fp->LogLevel, "%s: Oops, RTR in %s\n",
668              fp->link->name, State2Nam(fp->state));
669    break;
670  case ST_CLOSED:
671  case ST_STOPPED:
672  case ST_CLOSING:
673  case ST_STOPPING:
674  case ST_REQSENT:
675    (*fp->fn->SendTerminateAck)(fp, lhp->id);
676    break;
677  case ST_ACKRCVD:
678  case ST_ACKSENT:
679    (*fp->fn->SendTerminateAck)(fp, lhp->id);
680    NewState(fp, ST_REQSENT);
681    break;
682  case ST_OPENED:
683    (*fp->fn->LayerDown)(fp);
684    (*fp->fn->SendTerminateAck)(fp, lhp->id);
685    FsmInitRestartCounter(fp);
686    timer_Start(&fp->FsmTimer);	/* Start restart timer */
687    fp->restart = 0;
688    NewState(fp, ST_STOPPING);
689    (*fp->parent->LayerDown)(fp->parent->object, fp);
690    break;
691  }
692  mbuf_Free(bp);
693}
694
695static void
696FsmRecvTermAck(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp)
697/* RTA */
698{
699  switch (fp->state) {
700  case ST_CLOSING:
701    (*fp->fn->LayerFinish)(fp);
702    NewState(fp, ST_CLOSED);
703    (*fp->parent->LayerFinish)(fp->parent->object, fp);
704    break;
705  case ST_STOPPING:
706    (*fp->fn->LayerFinish)(fp);
707    NewState(fp, ST_STOPPED);
708    (*fp->parent->LayerFinish)(fp->parent->object, fp);
709    break;
710  case ST_ACKRCVD:
711    NewState(fp, ST_REQSENT);
712    break;
713  case ST_OPENED:
714    (*fp->fn->LayerDown)(fp);
715    FsmSendConfigReq(fp);
716    NewState(fp, ST_REQSENT);
717    (*fp->parent->LayerDown)(fp->parent->object, fp);
718    break;
719  }
720  mbuf_Free(bp);
721}
722
723static void
724FsmRecvConfigRej(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp)
725/* RCJ */
726{
727  struct fsm_decode dec;
728  int plen, flen;
729
730  plen = mbuf_Length(bp);
731  flen = ntohs(lhp->length) - sizeof *lhp;
732  if (plen < flen) {
733    mbuf_Free(bp);
734    return;
735  }
736
737  /*
738   * Check and process easy case
739   */
740  switch (fp->state) {
741  case ST_INITIAL:
742  case ST_STARTING:
743    log_Printf(fp->LogLevel, "%s: Oops, RCJ in %s.\n",
744              fp->link->name, State2Nam(fp->state));
745    mbuf_Free(bp);
746    return;
747  case ST_CLOSED:
748  case ST_STOPPED:
749    (*fp->fn->SendTerminateAck)(fp, lhp->id);
750    mbuf_Free(bp);
751    return;
752  case ST_CLOSING:
753  case ST_STOPPING:
754    mbuf_Free(bp);
755    return;
756  }
757
758  dec.ackend = dec.ack;
759  dec.nakend = dec.nak;
760  dec.rejend = dec.rej;
761  (*fp->fn->DecodeConfig)(fp, MBUF_CTOP(bp), flen, MODE_REJ, &dec);
762  if (flen < sizeof(struct fsmconfig))
763    log_Printf(fp->LogLevel, "  [EMPTY]\n");
764
765  switch (fp->state) {
766  case ST_REQSENT:
767  case ST_ACKSENT:
768    FsmInitRestartCounter(fp);
769    FsmSendConfigReq(fp);
770    break;
771  case ST_OPENED:
772    (*fp->fn->LayerDown)(fp);
773    FsmSendConfigReq(fp);
774    NewState(fp, ST_REQSENT);
775    (*fp->parent->LayerDown)(fp->parent->object, fp);
776    break;
777  case ST_ACKRCVD:
778    FsmSendConfigReq(fp);
779    NewState(fp, ST_REQSENT);
780    break;
781  }
782  mbuf_Free(bp);
783}
784
785static void
786FsmRecvCodeRej(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp)
787{
788  mbuf_Free(bp);
789}
790
791static void
792FsmRecvProtoRej(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp)
793{
794  struct physical *p = link2physical(fp->link);
795  u_short *sp, proto;
796
797  sp = (u_short *)MBUF_CTOP(bp);
798  proto = ntohs(*sp);
799  log_Printf(fp->LogLevel, "%s: -- Protocol 0x%04x (%s) was rejected!\n",
800            fp->link->name, proto, hdlc_Protocol2Nam(proto));
801
802  switch (proto) {
803  case PROTO_LQR:
804    if (p)
805      lqr_Stop(p, LQM_LQR);
806    else
807      log_Printf(LogERROR, "%s: FsmRecvProtoRej: Not a physical link !\n",
808                fp->link->name);
809    break;
810  case PROTO_CCP:
811    if (fp->proto == PROTO_LCP) {
812      fp = &fp->link->ccp.fsm;
813      (*fp->fn->LayerFinish)(fp);
814      switch (fp->state) {
815      case ST_CLOSED:
816      case ST_CLOSING:
817        NewState(fp, ST_CLOSED);
818      default:
819        NewState(fp, ST_STOPPED);
820        break;
821      }
822      (*fp->parent->LayerFinish)(fp->parent->object, fp);
823    }
824    break;
825  case PROTO_MP:
826    if (fp->proto == PROTO_LCP) {
827      struct lcp *lcp = fsm2lcp(fp);
828
829      if (lcp->want_mrru && lcp->his_mrru) {
830        log_Printf(LogPHASE, "%s: MP protocol reject is fatal !\n",
831                  fp->link->name);
832        fsm_Close(fp);
833      }
834    }
835    break;
836  }
837  mbuf_Free(bp);
838}
839
840static void
841FsmRecvEchoReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp)
842{
843  struct lcp *lcp = fsm2lcp(fp);
844  u_char *cp;
845  u_int32_t magic;
846
847  if (lcp) {
848    cp = MBUF_CTOP(bp);
849    magic = ntohl(*(u_int32_t *)cp);
850    if (magic != lcp->his_magic) {
851      log_Printf(fp->LogLevel, "%s: RecvEchoReq: Error: His magic is bad!!\n",
852                fp->link->name);
853      /* XXX: We should send terminate request */
854    }
855    if (fp->state == ST_OPENED) {
856      *(u_int32_t *)cp = htonl(lcp->want_magic); /* local magic */
857      fsm_Output(fp, CODE_ECHOREP, lhp->id, cp, mbuf_Length(bp));
858    }
859  }
860  mbuf_Free(bp);
861}
862
863static void
864FsmRecvEchoRep(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp)
865{
866  struct lcp *lcp = fsm2lcp(fp);
867  u_int32_t magic;
868
869  if (lcp) {
870    magic = ntohl(*(u_int32_t *)MBUF_CTOP(bp));
871    /* Tolerate echo replies with either magic number */
872    if (magic != 0 && magic != lcp->his_magic && magic != lcp->want_magic) {
873      log_Printf(LogWARN,
874                "%s: RecvEchoRep: Bad magic: expected 0x%08x, got: 0x%08x\n",
875	        fp->link->name, lcp->his_magic, magic);
876      /*
877       * XXX: We should send terminate request. But poor implementations may
878       * die as a result.
879       */
880    }
881    lqr_RecvEcho(fp, bp);
882  }
883  mbuf_Free(bp);
884}
885
886static void
887FsmRecvDiscReq(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp)
888{
889  mbuf_Free(bp);
890}
891
892static void
893FsmRecvIdent(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp)
894{
895  mbuf_Free(bp);
896}
897
898static void
899FsmRecvTimeRemain(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp)
900{
901  mbuf_Free(bp);
902}
903
904static void
905FsmRecvResetReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp)
906{
907  (*fp->fn->RecvResetReq)(fp);
908  /*
909   * All sendable compressed packets are queued in the PRI_NORMAL modem
910   * output queue.... dump 'em to the priority queue so that they arrive
911   * at the peer before our ResetAck.
912   */
913  link_SequenceQueue(fp->link);
914  fsm_Output(fp, CODE_RESETACK, lhp->id, NULL, 0);
915  mbuf_Free(bp);
916}
917
918static void
919FsmRecvResetAck(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp)
920{
921  (*fp->fn->RecvResetAck)(fp, lhp->id);
922  mbuf_Free(bp);
923}
924
925void
926fsm_Input(struct fsm *fp, struct mbuf *bp)
927{
928  int len;
929  struct fsmheader *lhp;
930  const struct fsmcodedesc *codep;
931
932  len = mbuf_Length(bp);
933  if (len < sizeof(struct fsmheader)) {
934    mbuf_Free(bp);
935    return;
936  }
937  lhp = (struct fsmheader *) MBUF_CTOP(bp);
938  if (lhp->code < fp->min_code || lhp->code > fp->max_code ||
939      lhp->code > sizeof FsmCodes / sizeof *FsmCodes) {
940    /*
941     * Use a private id.  This is really a response-type packet, but we
942     * MUST send a unique id for each REQ....
943     */
944    static u_char id;
945
946    fsm_Output(fp, CODE_CODEREJ, id++, MBUF_CTOP(bp), bp->cnt);
947    mbuf_Free(bp);
948    return;
949  }
950  bp->offset += sizeof(struct fsmheader);
951  bp->cnt -= sizeof(struct fsmheader);
952
953  codep = FsmCodes + lhp->code - 1;
954  if (lhp->id != fp->reqid && codep->check_reqid &&
955      Enabled(fp->bundle, OPT_IDCHECK)) {
956    log_Printf(fp->LogLevel, "%s: Recv%s(%d), dropped (expected %d)\n",
957	      fp->link->name, codep->name, lhp->id, fp->reqid);
958    return;
959  }
960
961  log_Printf(fp->LogLevel, "%s: Recv%s(%d) state = %s\n",
962	    fp->link->name, codep->name, lhp->id, State2Nam(fp->state));
963
964  if (log_IsKept(LogDEBUG))
965    mbuf_Log();
966
967  if (codep->inc_reqid && (lhp->id == fp->reqid ||
968      (!Enabled(fp->bundle, OPT_IDCHECK) && codep->check_reqid)))
969    fp->reqid++;	/* That's the end of that ``exchange''.... */
970
971  (*codep->recv)(fp, lhp, bp);
972
973  if (log_IsKept(LogDEBUG))
974    mbuf_Log();
975}
976
977void
978fsm_NullRecvResetReq(struct fsm *fp)
979{
980  log_Printf(fp->LogLevel, "%s: Oops - received unexpected reset req\n",
981            fp->link->name);
982}
983
984void
985fsm_NullRecvResetAck(struct fsm *fp, u_char id)
986{
987  log_Printf(fp->LogLevel, "%s: Oops - received unexpected reset ack\n",
988            fp->link->name);
989}
990
991void
992fsm_Reopen(struct fsm *fp)
993{
994  if (fp->state == ST_OPENED) {
995    (*fp->fn->LayerDown)(fp);
996    FsmInitRestartCounter(fp);
997    FsmSendConfigReq(fp);
998    NewState(fp, ST_REQSENT);
999    (*fp->parent->LayerDown)(fp->parent->object, fp);
1000  }
1001}
1002
1003void
1004fsm2initial(struct fsm *fp)
1005{
1006  if (fp->state == ST_STOPPED)
1007    fsm_Close(fp);
1008  if (fp->state > ST_INITIAL)
1009    fsm_Down(fp);
1010  if (fp->state > ST_INITIAL)
1011    fsm_Close(fp);
1012}
1013