fsm.c revision 28974
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 $ 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 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} 765