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