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