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