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