fsm.c revision 6059
1139825Simp/*
21541Srgrimes *		PPP Finite State Machine for LCP/IPCP
31541Srgrimes *
41541Srgrimes *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
51541Srgrimes *
61541Srgrimes *   Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
71541Srgrimes *
81541Srgrimes * Redistribution and use in source and binary forms are permitted
91541Srgrimes * provided that the above copyright notice and this paragraph are
101541Srgrimes * duplicated in all such forms and that any documentation,
111541Srgrimes * advertising materials, and other materials related to such
121541Srgrimes * distribution and use acknowledge that the software was developed
131541Srgrimes * by the Internet Initiative Japan, Inc.  The name of the
141541Srgrimes * IIJ may not be used to endorse or promote products derived
151541Srgrimes * from this software without specific prior written permission.
161541Srgrimes * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
171541Srgrimes * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
181541Srgrimes * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
191541Srgrimes *
201541Srgrimes * $Id:$
211541Srgrimes *
221541Srgrimes *  TODO:
231541Srgrimes *		o Refer loglevel for log output
241541Srgrimes *		o Better option log display
251541Srgrimes */
261541Srgrimes#include "fsm.h"
271541Srgrimes#include "hdlc.h"
281541Srgrimes#include "lqr.h"
291541Srgrimes#include "lcpproto.h"
301541Srgrimes#include "lcp.h"
311541Srgrimes
32116226Sobrienvoid FsmSendConfigReq(struct fsm *fp);
33116226Sobrienvoid FsmSendTerminateReq(struct fsm *fp);
34116226Sobrienvoid FsmInitRestartCounter(struct fsm *fp);
351541Srgrimesvoid FsmTimeout(struct fsm *fp);
361541Srgrimes
371541Srgrimeschar *StateNames[] = {
3876166Smarkm  "Initial", "Starting", "Closed", "Stopped", "Closing", "Stopping",
3976166Smarkm  "Req-Sent", "Ack-Rcvd", "Ack-Sent", "Opend",
4076166Smarkm};
4134924Sbde
42248084Sattiliovoid
4374927SjhbFsmInit(fp)
4412662Sdgstruct fsm *fp;
4593823Sdillon{
4612662Sdg#ifdef DEBUG
471541Srgrimes  logprintf("FsmInit\n");
4840794Speter#endif
4912726Sbde  fp->state = ST_INITIAL;
5012662Sdg  fp->reqid = 1;
5112662Sdg  fp->restart = 1;
5212662Sdg  fp->maxconfig = 3;
5312662Sdg}
541541Srgrimes
551541Srgrimesvoid
56170170SattilioNewState(fp, new)
571541Srgrimesstruct fsm *fp;
5862622Sjhbint new;
59228449Seadler{
6062622Sjhb  LogPrintf(LOG_LCP, "%s: state change %s --> %s\n",
61228449Seadler	  fp->name, StateNames[fp->state], StateNames[new]);
6262622Sjhb  fp->state = new;
63228449Seadler  if ((new >= ST_INITIAL && new <= ST_STOPPED) || (new == ST_OPENED))
6462622Sjhb    StopTimer(&fp->FsmTimer);
65228449Seadler}
6662622Sjhb
67228449Seadlervoid
6862622SjhbFsmOutput(fp, code, id, ptr, count)
69228449Seadlerstruct fsm *fp;
7062622Sjhbu_int code, id;
71228449Seadleru_char *ptr;
7262622Sjhbint count;
73228449Seadler{
7412286Sphk  int plen;
75136404Speter  struct fsmheader lh;
76136404Speter  struct mbuf *bp;
77136404Speter
78181887Sjulian  plen =  sizeof(struct fsmheader) + count;
79136404Speter  lh.code = code;
80136404Speter  lh.id = id;
811541Srgrimes  lh.length = htons(plen);
82136404Speter  bp = mballoc(plen, MB_FSM);
83136404Speter  bcopy(&lh, MBUF_CTOP(bp), sizeof(struct fsmheader));
84136404Speter  if (count)
85136404Speter    bcopy(ptr, MBUF_CTOP(bp) + sizeof(struct fsmheader), count);
86136404Speter#ifdef DEBUG
87136404Speter  DumpBp(bp);
88136404Speter#endif
89136404Speter  HdlcOutput(PRI_NORMAL, fp->proto, bp);
90136404Speter}
91136404Speter
92187658Sjhbvoid
93187658SjhbFsmOpen(fp)
94187658Sjhbstruct fsm *fp;
95136404Speter{
96307929Sglebius  switch (fp->state) {
97307929Sglebius  case ST_INITIAL:
98307929Sglebius    (fp->LayerStart)(fp);
99307929Sglebius    NewState(fp, ST_STARTING);
100307929Sglebius    break;
101307929Sglebius  case ST_STARTING:
102307929Sglebius    break;
103307929Sglebius  case ST_CLOSED:
104307929Sglebius    if (fp->open_mode == OPEN_PASSIVE) {
105307929Sglebius      NewState(fp, ST_STOPPED);
106307929Sglebius    } else {
107307929Sglebius      FsmInitRestartCounter(fp);
108307929Sglebius      FsmSendConfigReq(fp);
109307929Sglebius      NewState(fp, ST_REQSENT);
110307929Sglebius    }
11112286Sphk    break;
11262573Sphk  case ST_STOPPED:	/* XXX: restart option */
1131541Srgrimes  case ST_REQSENT:
114164437Sru  case ST_ACKRCVD:
11512286Sphk  case ST_ACKSENT:
116307929Sglebius  case ST_OPENED:	/* XXX: restart option */
11799072Sjulian    break;
1181541Srgrimes  case ST_CLOSING:	/* XXX: restart option */
119164437Sru  case ST_STOPPING:	/* XXX: restart option */
120307929Sglebius    NewState(fp, ST_STOPPING);
1211541Srgrimes    break;
1221541Srgrimes  }
1231541Srgrimes}
12474927Sjhb
12583366Sjulianvoid
1261541SrgrimesFsmUp(fp)
1271541Srgrimesstruct fsm *fp;
128177368Sjeff{
12999072Sjulian  switch (fp->state) {
13099072Sjulian  case ST_INITIAL:
131177368Sjeff    NewState(fp, ST_CLOSED);
1321541Srgrimes    break;
1331541Srgrimes  case ST_STARTING:
13499072Sjulian    FsmInitRestartCounter(fp);
13599072Sjulian    FsmSendConfigReq(fp);
136170307Sjeff    NewState(fp, ST_REQSENT);
13799072Sjulian    break;
138103216Sjulian  default:
139177085Sjeff    LogPrintf(LOG_LCP, "%s: Oops, Up at %s\n",
140164437Sru	    fp->name, StateNames[fp->state]);
141307929Sglebius    break;
142307929Sglebius  }
143307929Sglebius}
144307929Sglebius
145307929Sglebiusvoid
146307929SglebiusFsmDown(fp)
147307929Sglebiusstruct fsm *fp;
148307929Sglebius{
149307929Sglebius  switch (fp->state) {
15099072Sjulian  case ST_CLOSED:
1511541Srgrimes  case ST_CLOSING:
152103216Sjulian    NewState(fp, ST_INITIAL);
153164437Sru    break;
154103216Sjulian  case ST_STOPPED:
15599072Sjulian    (fp->LayerStart)(fp);
15699072Sjulian    /* Fall into.. */
157164437Sru  case ST_STOPPING:
158170307Sjeff  case ST_REQSENT:
15999072Sjulian  case ST_ACKRCVD:
16099072Sjulian  case ST_ACKSENT:
16199072Sjulian    NewState(fp, ST_STARTING);
16299072Sjulian    break;
163170307Sjeff  case ST_OPENED:
16471572Sjhb    (fp->LayerDown)(fp);
1651541Srgrimes    NewState(fp, ST_STARTING);
166177368Sjeff    break;
1671541Srgrimes  }
16874927Sjhb}
1691541Srgrimes
1701541Srgrimesvoid
1711541SrgrimesFsmClose(fp)
17295112Salcstruct fsm *fp;
17375523Salfred{
17442957Sdillon  switch (fp->state) {
175284100Sjhb  case ST_STARTING:
176284100Sjhb    NewState(fp, ST_INITIAL);
177284100Sjhb    break;
17842957Sdillon  case ST_STOPPED:
179244043Salc    NewState(fp, ST_CLOSED);
180124083Salc    break;
181124083Salc  case ST_STOPPING:
182124083Salc    NewState(fp, ST_CLOSING);
18342957Sdillon    break;
184108585Salc  case ST_OPENED:
185164429Sru    (fp->LayerDown)(fp);
186164429Sru    /* Fall down */
187164429Sru  case ST_REQSENT:
188164429Sru  case ST_ACKRCVD:
189164429Sru  case ST_ACKSENT:
190164429Sru    FsmInitRestartCounter(fp);
191164429Sru    FsmSendTerminateReq(fp);
192307929Sglebius    NewState(fp, ST_CLOSING);
193307929Sglebius    break;
194307929Sglebius  }
195307929Sglebius}
196307929Sglebius
197307929Sglebius/*
198307929Sglebius *	Send functions
199307929Sglebius */
200307929Sglebiusvoid
201164437SruFsmSendConfigReq(fp)
202164437Srustruct fsm *fp;
203307929Sglebius{
204164437Sru  if (--fp->maxconfig > 0) {
205164437Sru    (fp->SendConfigReq)(fp);
2061541Srgrimes    StartTimer(&fp->FsmTimer);	/* Start restart timer */
20718169Sdyson    fp->restart--;		/* Decrement restart counter */
2081541Srgrimes  } else {
209164437Sru    FsmClose(fp);
210164437Sru  }
211307929Sglebius}
212164437Sru
213164437Sruvoid
2141541SrgrimesFsmSendTerminateReq(fp)
2151541Srgrimesstruct fsm *fp;
2161541Srgrimes{
21795112Salc  LogPrintf(LOG_LCP, "%s: SendTerminateReq.\n", fp->name);
218170170Sattilio  FsmOutput(fp, CODE_TERMREQ, fp->reqid++, NULL, 0);
219164437Sru  (fp->SendTerminateReq)(fp);
2201541Srgrimes  StartTimer(&fp->FsmTimer);	/* Start restart timer */
22112286Sphk  fp->restart--;		/* Decrement restart counter */
22293823Sdillon}
22393823Sdillon
22493823Sdillonstatic void
22593823SdillonFsmSendConfigAck(fp, lhp, option, count)
22693823Sdillonstruct fsm *fp;
22793823Sdillonstruct fsmheader *lhp;
22893823Sdillonu_char *option;
22993823Sdillonint count;
23093823Sdillon{
23193823Sdillon  LogPrintf(LOG_LCP, "%s:  SendConfigAck(%s)\n", fp->name, StateNames[fp->state]);
23293823Sdillon  FsmOutput(fp, CODE_CONFIGACK, lhp->id, option, count);
23393823Sdillon}
23493823Sdillon
23593823Sdillonstatic void
23693823SdillonFsmSendConfigRej(fp, lhp, option, count)
23793823Sdillonstruct fsm *fp;
238170170Sattiliostruct fsmheader *lhp;
23993823Sdillonu_char *option;
24093823Sdillonint count;
241218592Sjmallett{
24293823Sdillon  LogPrintf(LOG_LCP, "%s:  SendConfigRej(%s)\n", fp->name, StateNames[fp->state]);
24393823Sdillon  FsmOutput(fp, CODE_CONFIGREJ, lhp->id, option, count);
24493823Sdillon}
245144970Sjhb
24693823Sdillonstatic void
24793823SdillonFsmSendConfigNak(fp, lhp, option, count)
248187658Sjhbstruct fsm *fp;
24946381Sbillfstruct fsmheader *lhp;
25046381Sbillfu_char *option;
251141696Sphkint count;
252141630Sphk{
253141630Sphk  LogPrintf(LOG_LCP, "%s:  SendConfigNak(%s)\n",
254141630Sphk	    fp->name, StateNames[fp->state]);
255141630Sphk  FsmOutput(fp, CODE_CONFIGNAK, lhp->id, option, count);
25640794Speter}
25793823Sdillon
258228498Seadler/*
259228498Seadler *	Timeout actions
260228498Seadler */
261228498Seadlervoid
262228498SeadlerFsmTimeout(fp)
263228498Seadlerstruct fsm *fp;
26493823Sdillon{
265228449Seadler  if (fp->restart) {
266228449Seadler    switch (fp->state) {
267228449Seadler    case ST_CLOSING:
268228449Seadler    case ST_STOPPING:
269228449Seadler      FsmSendTerminateReq(fp);
270228498Seadler      break;
271246032Szont    case ST_REQSENT:
272228498Seadler    case ST_ACKSENT:
273228498Seadler      FsmSendConfigReq(fp);
274228498Seadler      break;
275228498Seadler    case ST_ACKRCVD:
276228498Seadler      FsmSendConfigReq(fp);
277228498Seadler      NewState(fp, ST_REQSENT);
278228498Seadler      break;
279228498Seadler    }
280228498Seadler    StartTimer(&fp->FsmTimer);
281228498Seadler  } else {
282228498Seadler    switch (fp->state) {
283228498Seadler    case ST_CLOSING:
284228498Seadler      NewState(fp, ST_CLOSED);
285228498Seadler      (fp->LayerFinish)(fp);
286228498Seadler      break;
287228498Seadler    case ST_STOPPING:
288228498Seadler      NewState(fp, ST_STOPPED);
289228498Seadler      (fp->LayerFinish)(fp);
290228498Seadler      break;
291228498Seadler    case ST_REQSENT:		/* XXX: 3p */
292228498Seadler    case ST_ACKSENT:
293228498Seadler    case ST_ACKRCVD:
294228498Seadler      NewState(fp, ST_STOPPED);
295228498Seadler      (fp->LayerFinish)(fp);
296228498Seadler      break;
297228498Seadler    }
298228498Seadler  }
299228498Seadler}
300228498Seadler
301228498Seadlervoid
302228498SeadlerFsmInitRestartCounter(fp)
303228498Seadlerstruct fsm *fp;
304228498Seadler{
305228498Seadler  StopTimer(&fp->FsmTimer);
306228498Seadler  fp->FsmTimer.state = TIMER_STOPPED;
307228498Seadler  fp->FsmTimer.func = FsmTimeout;
308228498Seadler  fp->FsmTimer.arg = (void *)fp;
309228498Seadler  (fp->InitRestartCounter)(fp);
310228498Seadler}
311228498Seadler
312228498Seadler/*
313228498Seadler *   Actions when receive packets
314228498Seadler */
315228449Seadlervoid
316228449SeadlerFsmRecvConfigReq(fp, lhp, bp)			/* RCR */
317228449Seadlerstruct fsm *fp;
318struct fsmheader *lhp;
319struct mbuf *bp;
320{
321  int plen;
322  int ackaction = 0;
323
324  plen = plength(bp);
325  if (plen < sizeof(struct fsmconfig)) {
326logprintf("** plen = %d\n", plen);
327    pfree(bp);
328    return;
329  }
330
331  /*
332   *  Check and process easy case
333   */
334  switch (fp->state) {
335  case ST_INITIAL:
336  case ST_STARTING:
337    LogPrintf(LOG_LCP, "%s: Oops, RCR in %s.\n",
338	    fp->name, StateNames[fp->state]);
339    pfree(bp);
340    return;
341  case ST_CLOSED:
342    (fp->SendTerminateAck)(fp);
343    pfree(bp);
344    return;
345  case ST_CLOSING:
346  case ST_STOPPING:
347logprintf("## state = %d\n", fp->state);
348    pfree(bp);
349    return;
350  }
351
352  (fp->DecodeConfig)(bp, MODE_REQ);
353
354  if (nakp == NakBuff && rejp == RejBuff)
355    ackaction = 1;
356
357  switch (fp->state) {
358  case ST_OPENED:
359    (fp->LayerDown)(fp);
360    FsmSendConfigReq(fp);
361    break;
362  case ST_STOPPED:
363    FsmInitRestartCounter(fp);
364    FsmSendConfigReq(fp);
365    break;
366  }
367
368  if (rejp != RejBuff)
369    FsmSendConfigRej(fp, lhp, RejBuff, rejp - RejBuff);
370  if (nakp != NakBuff)
371    FsmSendConfigNak(fp, lhp, NakBuff, nakp - NakBuff);
372  if (ackaction)
373    FsmSendConfigAck(fp, lhp, AckBuff, ackp - AckBuff);
374
375  switch (fp->state) {
376  case ST_STOPPED:
377  case ST_OPENED:
378    if (ackaction)
379      NewState(fp, ST_ACKSENT);
380    else
381      NewState(fp, ST_REQSENT);
382    break;
383  case ST_REQSENT:
384    if (ackaction)
385      NewState(fp, ST_ACKSENT);
386    break;
387  case ST_ACKRCVD:
388    if (ackaction) {
389      NewState(fp, ST_OPENED);
390      (fp->LayerUp)(fp);
391    }
392    break;
393  case ST_ACKSENT:
394    if (!ackaction)
395      NewState(fp, ST_REQSENT);
396    break;
397  }
398  pfree(bp);
399}
400
401void
402FsmRecvConfigAck(fp, lhp, bp)			/* RCA */
403struct fsm *fp;
404struct fsmheader *lhp;
405struct mbuf *bp;
406{
407  switch (fp->state) {
408  case ST_CLOSED:
409  case ST_STOPPED:
410    (fp->SendTerminateAck)(fp);
411    break;
412  case ST_CLOSING:
413  case ST_STOPPING:
414    break;
415  case ST_REQSENT:
416    FsmInitRestartCounter(fp);
417    NewState(fp, ST_ACKRCVD);
418    break;
419  case ST_ACKRCVD:
420    FsmSendConfigReq(fp);
421    NewState(fp, ST_REQSENT);
422    break;
423  case ST_ACKSENT:
424    FsmInitRestartCounter(fp);
425    NewState(fp, ST_OPENED);
426    (fp->LayerUp)(fp);
427    break;
428  case ST_OPENED:
429    (fp->LayerDown)(fp);
430    FsmSendConfigReq(fp);
431    NewState(fp, ST_REQSENT);
432    break;
433  }
434  pfree(bp);
435}
436
437void
438FsmRecvConfigNak(fp, lhp, bp)			/* RCN */
439struct fsm *fp;
440struct fsmheader *lhp;
441struct mbuf *bp;
442{
443  int plen;
444
445  plen = plength(bp);
446  if (plen < sizeof(struct fsmconfig)) {
447    pfree(bp);
448    return;
449  }
450
451  /*
452   *  Check and process easy case
453   */
454  switch (fp->state) {
455  case ST_INITIAL:
456  case ST_STARTING:
457    LogPrintf(LOG_LCP, "%s: Oops, RCN in %s.\n",
458	    fp->name, StateNames[fp->state]);
459    pfree(bp);
460    return;
461  case ST_CLOSED:
462  case ST_STOPPED:
463    (fp->SendTerminateAck)(fp);
464    pfree(bp);
465    return;
466  case ST_CLOSING:
467  case ST_STOPPING:
468    pfree(bp);
469    return;
470  }
471
472  (fp->DecodeConfig)(bp, MODE_NAK);
473
474  switch (fp->state) {
475  case ST_REQSENT:
476  case ST_ACKSENT:
477    FsmInitRestartCounter(fp);
478    FsmSendConfigReq(fp);
479    break;
480  case ST_OPENED:
481    (fp->LayerDown)(fp);
482    /* Fall down */
483  case ST_ACKRCVD:
484    FsmSendConfigReq(fp);
485    NewState(fp, ST_REQSENT);
486    break;
487  }
488
489  pfree(bp);
490}
491
492void
493FsmRecvTermReq(fp, lhp, bp)				/* RTR */
494struct fsm *fp;
495struct fsmheader *lhp;
496struct mbuf *bp;
497{
498  switch (fp->state) {
499  case ST_INITIAL:
500  case ST_STARTING:
501    LogPrintf(LOG_LCP, "%s: Oops, RTR in %s\n", fp->name,
502	    StateNames[fp->state]);
503    break;
504  case ST_CLOSED:
505  case ST_STOPPED:
506  case ST_CLOSING:
507  case ST_STOPPING:
508  case ST_REQSENT:
509    (fp->SendTerminateAck)(fp);
510    break;
511  case ST_ACKRCVD:
512  case ST_ACKSENT:
513    (fp->SendTerminateAck)(fp);
514    NewState(fp, ST_REQSENT);
515    break;
516  case ST_OPENED:
517    (fp->LayerDown)(fp);
518    /* Zero Restart counter */
519    (fp->SendTerminateAck)(fp);
520    NewState(fp, ST_STOPPING);
521    break;
522  }
523  pfree(bp);
524}
525
526void
527FsmRecvTermAck(fp, lhp, bp)			/* RTA */
528struct fsm *fp;
529struct fsmheader *lhp;
530struct mbuf *bp;
531{
532  switch (fp->state) {
533  case ST_CLOSING:
534    NewState(fp, ST_CLOSED);
535    (fp->LayerFinish)(fp);
536    break;
537  case ST_STOPPING:
538    NewState(fp, ST_STOPPED);
539    (fp->LayerFinish)(fp);
540    break;
541  case ST_ACKRCVD:
542    NewState(fp, ST_REQSENT);
543    break;
544  case ST_OPENED:
545    (fp->LayerDown)(fp);
546    FsmSendConfigReq(fp);
547    NewState(fp, ST_REQSENT);
548    break;
549  }
550  pfree(bp);
551}
552
553void
554FsmRecvConfigRej(fp, lhp, bp)			/* RCJ */
555struct fsm *fp;
556struct fsmheader *lhp;
557struct mbuf *bp;
558{
559  int plen;
560
561  plen = plength(bp);
562  if (plen < sizeof(struct fsmconfig)) {
563    pfree(bp);
564    return;
565  }
566  LogPrintf(LOG_LCP, "%s: RecvConfigRej.\n", fp->name);
567
568  /*
569   *  Check and process easy case
570   */
571  switch (fp->state) {
572  case ST_INITIAL:
573  case ST_STARTING:
574    LogPrintf(LOG_LCP, "%s: Oops, RCJ in %s.\n",
575	    fp->name, StateNames[fp->state]);
576    pfree(bp);
577    return;
578  case ST_CLOSED:
579  case ST_STOPPED:
580    (fp->SendTerminateAck)(fp);
581    pfree(bp);
582    return;
583  case ST_CLOSING:
584  case ST_STOPPING:
585    pfree(bp);
586    return;
587  }
588
589  (fp->DecodeConfig)(bp, MODE_REJ);
590
591  switch (fp->state) {
592  case ST_REQSENT:
593  case ST_ACKSENT:
594    FsmInitRestartCounter(fp);
595    FsmSendConfigReq(fp);
596    break;
597  case ST_OPENED:
598    (fp->LayerDown)(fp);
599    /* Fall down */
600  case ST_ACKRCVD:
601    FsmSendConfigReq(fp);
602    NewState(fp, ST_REQSENT);
603    break;
604  }
605  pfree(bp);
606}
607
608void
609FsmRecvCodeRej(fp, lhp, bp)
610struct fsm *fp;
611struct fsmheader *lhp;
612struct mbuf *bp;
613{
614  LogPrintf(LOG_LCP, "%s: RecvCodeRej\n", fp->name);
615  pfree(bp);
616}
617
618void
619FsmRecvProtoRej(fp, lhp, bp)
620struct fsm *fp;
621struct fsmheader *lhp;
622struct mbuf *bp;
623{
624  u_short *sp, proto;
625
626  sp = (u_short *)MBUF_CTOP(bp);
627  proto = ntohs(*sp);
628  LogPrintf(LOG_LCP, "-- Protocol (%04x) was rejected.\n", proto);
629
630  switch (proto) {
631  case PROTO_LQR:
632    StopLqr(LQM_LQR);
633    break;
634  case PROTO_CCP:
635    fp = &CcpFsm;
636    (fp->LayerFinish)(fp);
637    switch (fp->state) {
638    case ST_CLOSED:
639    case ST_CLOSING:
640      NewState(fp, ST_CLOSED);
641    default:
642      NewState(fp, ST_STOPPED);
643      break;
644    }
645    break;
646  }
647  pfree(bp);
648}
649
650void
651FsmRecvEchoReq(fp, lhp, bp)
652struct fsm *fp;
653struct fsmheader *lhp;
654struct mbuf *bp;
655{
656  u_char *cp;
657  u_long *lp, magic;
658
659  cp = MBUF_CTOP(bp);
660  lp = (u_long *)cp;
661  magic = ntohl(*lp);
662  if (magic != LcpInfo.his_magic) {
663    logprintf("RecvEchoReq: his magic is bad!!\n");
664    /* XXX: We should send terminate request */
665  }
666
667  if (fp->state == ST_OPENED) {
668    *lp = htonl(LcpInfo.want_magic);	/* Insert local magic number */
669    LogPrintf(LOG_LCP, "%s:  SendEchoRep(%s)\n", fp->name, StateNames[fp->state]);
670    FsmOutput(fp, CODE_ECHOREP, lhp->id, cp, plength(bp));
671  }
672  pfree(bp);
673}
674
675void
676FsmRecvEchoRep(fp, lhp, bp)
677struct fsm *fp;
678struct fsmheader *lhp;
679struct mbuf *bp;
680{
681  u_long *lp, magic;
682
683  lp = (u_long *)MBUF_CTOP(bp);
684  magic = ntohl(*lp);
685  if (magic != 0 && magic != LcpInfo.his_magic) {
686    logprintf("RecvEchoRep: his magic is wrong! expect: %x got: %x\n",
687	LcpInfo.his_magic, magic);
688    /*
689     *  XXX: We should send terminate request. But poor implementation
690     *       may die as a result.
691     */
692  }
693  RecvEchoLqr(bp);
694  pfree(bp);
695}
696
697void
698FsmRecvDiscReq(fp, lhp, bp)
699struct fsm *fp;
700struct fsmheader *lhp;
701struct mbuf *bp;
702{
703  LogPrintf(LOG_LCP, "%s: RecvDiscReq\n", fp->name);
704  pfree(bp);
705}
706
707void
708FsmRecvIdent(fp, lhp, bp)
709struct fsm *fp;
710struct fsmheader *lhp;
711struct mbuf *bp;
712{
713  LogPrintf(LOG_LCP, "%s: RecvIdent\n", fp->name);
714  pfree(bp);
715}
716
717void
718FsmRecvTimeRemain(fp, lhp, bp)
719struct fsm *fp;
720struct fsmheader *lhp;
721struct mbuf *bp;
722{
723  LogPrintf(LOG_LCP, "%s: RecvTimeRemain\n", fp->name);
724  pfree(bp);
725}
726
727void
728FsmRecvResetReq(fp, lhp, bp)
729struct fsm *fp;
730struct fsmheader *lhp;
731struct mbuf *bp;
732{
733  LogPrintf(LOG_LCP, "%s: RecvResetReq\n", fp->name);
734  CcpRecvResetReq(fp);
735  LogPrintf(LOG_LCP, "%s: SendResetAck\n", fp->name);
736  FsmOutput(fp, CODE_RESETACK, fp->reqid, NULL, 0);
737  pfree(bp);
738}
739
740void
741FsmRecvResetAck(fp, lhp, bp)
742struct fsm *fp;
743struct fsmheader *lhp;
744struct mbuf *bp;
745{
746  LogPrintf(LOG_LCP, "%s: RecvResetAck\n", fp->name);
747  fp->reqid++;
748  pfree(bp);
749}
750
751struct fsmcodedesc FsmCodes[] = {
752 { FsmRecvConfigReq,  "Configure Request", },
753 { FsmRecvConfigAck,  "Configure Ack", },
754 { FsmRecvConfigNak,  "Configure Nak", },
755 { FsmRecvConfigRej,  "Configure Reject", },
756 { FsmRecvTermReq,    "Terminate Request", },
757 { FsmRecvTermAck,    "Terminate Ack", },
758 { FsmRecvCodeRej,    "Code Reject", },
759 { FsmRecvProtoRej,   "Protocol Reject", },
760 { FsmRecvEchoReq,    "Echo Request", },
761 { FsmRecvEchoRep,    "Echo Reply", },
762 { FsmRecvDiscReq,    "Discard Request", },
763 { FsmRecvIdent,      "Ident", },
764 { FsmRecvTimeRemain, "Time Remain", },
765 { FsmRecvResetReq,   "Reset Request", },
766 { FsmRecvResetAck,   "Reset Ack", },
767};
768
769void
770FsmInput(fp, bp)
771struct fsm *fp;
772struct mbuf *bp;
773{
774  int len;
775  struct fsmheader *lhp;
776  struct fsmcodedesc *codep;
777
778  len = plength(bp);
779  if (len < sizeof(struct fsmheader)) {
780    pfree(bp);
781    return;
782  }
783  lhp = (struct fsmheader *)MBUF_CTOP(bp);
784  if (lhp->code == 0 || lhp->code > fp->max_code) {
785    pfree(bp);		/* XXX: Should send code reject */
786    return;
787  }
788
789  bp->offset += sizeof(struct fsmheader);
790  bp->cnt -= sizeof(struct fsmheader);
791
792  codep = FsmCodes + lhp->code - 1;
793  LogPrintf(LOG_LCP, "%s: Received %s (%d) state = %s (%d)\n",
794    fp->name, codep->name, lhp->code, StateNames[fp->state], fp->state);
795#ifdef DEBUG
796  LogMemory();
797#endif
798  (codep->action)(fp, lhp, bp);
799#ifdef DEBUG
800  LogMemory();
801#endif
802}
803