Annotation of embedaddon/mpd/src/fsm.c, revision 1.1
1.1 ! misho 1:
! 2: /*
! 3: * fsm.c
! 4: *
! 5: * Written by Toshiharu OHNO <tony-o@iij.ad.jp>
! 6: * Copyright (c) 1993, Internet Initiative Japan, Inc. All rights reserved.
! 7: * See ``COPYRIGHT.iij''
! 8: *
! 9: * Rewritten by Archie Cobbs <archie@freebsd.org>
! 10: * Copyright (c) 1995-1999 Whistle Communications, Inc. All rights reserved.
! 11: * See ``COPYRIGHT.whistle''
! 12: */
! 13:
! 14: #include "ppp.h"
! 15: #include "fsm.h"
! 16: #include "ngfunc.h"
! 17: #include "util.h"
! 18:
! 19: /*
! 20: * DEFINITIONS
! 21: */
! 22:
! 23: #define FSM_MAXCONFIG 10
! 24: #define FSM_MAXNAK 10
! 25: #define FSM_MAX_OPTS 100
! 26: #define FSM_MAXTERMINATE 2
! 27: #define FSM_MAXFAILURE 5
! 28:
! 29: /* FSM restart options */
! 30:
! 31: /* #define RESTART_OPENED */
! 32: /* #define RESTART_CLOSING */
! 33: /* #define RESTART_STOPPED */
! 34:
! 35: struct fsmcodedesc {
! 36: void (*action)(Fsm fp, FsmHeader hdr, Mbuf bp);
! 37: const char *name;
! 38: };
! 39:
! 40: /* Size of REQ, ACK, NAK, and REJ buffers */
! 41:
! 42: #define REQ_BUFFER_SIZE 256
! 43: #define REJ_BUFFER_SIZE 256
! 44: #define ACK_BUFFER_SIZE 256
! 45: #define NAK_BUFFER_SIZE 256
! 46:
! 47: /*
! 48: * INTERNAL FUNCTIONS
! 49: */
! 50:
! 51: static void FsmNewState(Fsm f, enum fsm_state state);
! 52:
! 53: static void FsmSendConfigReq(Fsm fp);
! 54: static void FsmSendTerminateReq(Fsm fp);
! 55: static void FsmSendTerminateAck(Fsm fp);
! 56: static void FsmInitRestartCounter(Fsm fp, int value);
! 57: static void FsmInitMaxFailure(Fsm fp, int value);
! 58: static void FsmInitMaxConfig(Fsm fp, int value);
! 59: static void FsmTimeout(void *arg);
! 60:
! 61: static void FsmRecvConfigReq(Fsm fp, FsmHeader lhp, Mbuf bp);
! 62: static void FsmRecvConfigAck(Fsm fp, FsmHeader lhp, Mbuf bp);
! 63: static void FsmRecvConfigNak(Fsm fp, FsmHeader lhp, Mbuf bp);
! 64: static void FsmRecvTermReq(Fsm fp, FsmHeader lhp, Mbuf bp);
! 65: static void FsmRecvTermAck(Fsm fp, FsmHeader lhp, Mbuf bp);
! 66: static void FsmRecvConfigRej(Fsm fp, FsmHeader lhp, Mbuf bp);
! 67: static void FsmRecvCodeRej(Fsm fp, FsmHeader lhp, Mbuf bp);
! 68: static void FsmRecvProtoRej(Fsm fp, FsmHeader lhp, Mbuf bp);
! 69: static void FsmRecvEchoReq(Fsm fp, FsmHeader lhp, Mbuf bp);
! 70: static void FsmRecvEchoRep(Fsm fp, FsmHeader lhp, Mbuf bp);
! 71: static void FsmRecvDiscReq(Fsm fp, FsmHeader lhp, Mbuf bp);
! 72: static void FsmRecvIdent(Fsm fp, FsmHeader lhp, Mbuf bp);
! 73: static void FsmRecvTimeRemain(Fsm fp, FsmHeader lhp, Mbuf bp);
! 74: static void FsmRecvResetReq(Fsm fp, FsmHeader lhp, Mbuf bp);
! 75: static void FsmRecvResetAck(Fsm fp, FsmHeader lhp, Mbuf bp);
! 76: static void FsmRecvVendor(Fsm fp, FsmHeader lhp, Mbuf bp);
! 77: static void FsmRecvRxjPlus(Fsm fp);
! 78:
! 79: static void FsmLayerUp(Fsm fp);
! 80: static void FsmLayerDown(Fsm fp);
! 81: static void FsmLayerStart(Fsm fp);
! 82: static void FsmLayerFinish(Fsm fp);
! 83:
! 84: static Mbuf FsmCheckMagic(Fsm fp, Mbuf bp);
! 85: static void FsmEchoTimeout(void *arg);
! 86: static void FsmDecodeBuffer(Fsm fp, u_char *buf, int size, int mode);
! 87: static int FsmExtractOptions(Fsm fp, u_char *data,
! 88: int dlen, FsmOption opts, int max);
! 89:
! 90: /*
! 91: * GLOBAL VARIABLES
! 92: */
! 93:
! 94: u_int gAckSize, gNakSize, gRejSize;
! 95:
! 96: /*
! 97: * INTERNAL VARIABLES
! 98: */
! 99:
! 100: /*
! 101: * It's OK for these to be statically allocated, because we always
! 102: * do our work with them all in one whole step without stopping.
! 103: */
! 104:
! 105: static u_char gRejBuf[REJ_BUFFER_SIZE];
! 106: static u_char gAckBuf[ACK_BUFFER_SIZE];
! 107: static u_char gNakBuf[NAK_BUFFER_SIZE];
! 108:
! 109: static const struct fsmcodedesc FsmCodes[] = {
! 110: { FsmRecvVendor, "Vendor Packet" },
! 111: { FsmRecvConfigReq, "Configure Request" },
! 112: { FsmRecvConfigAck, "Configure Ack" },
! 113: { FsmRecvConfigNak, "Configure Nak" },
! 114: { FsmRecvConfigRej, "Configure Reject" },
! 115: { FsmRecvTermReq, "Terminate Request" },
! 116: { FsmRecvTermAck, "Terminate Ack" },
! 117: { FsmRecvCodeRej, "Code Reject" },
! 118: { FsmRecvProtoRej, "Protocol Reject" },
! 119: { FsmRecvEchoReq, "Echo Request" },
! 120: { FsmRecvEchoRep, "Echo Reply" },
! 121: { FsmRecvDiscReq, "Discard Request" },
! 122: { FsmRecvIdent, "Ident" },
! 123: { FsmRecvTimeRemain, "Time Remain" },
! 124: { FsmRecvResetReq, "Reset Request" },
! 125: { FsmRecvResetAck, "Reset Ack" },
! 126: };
! 127:
! 128: #define NUM_FSM_CODES (sizeof(FsmCodes) / sizeof(*FsmCodes))
! 129:
! 130: /*
! 131: * FsmInit()
! 132: *
! 133: * Initialize FSM structure and install some default values
! 134: */
! 135:
! 136: void
! 137: FsmInit(Fsm fp, FsmType type, void *arg)
! 138: {
! 139: memset(fp, 0, sizeof(*fp));
! 140: fp->type = type;
! 141: fp->arg = arg;
! 142: fp->log = LG_FSM | type->log;
! 143: fp->log2 = LG_FSM | type->log2;
! 144: fp->conf.maxconfig = FSM_MAXCONFIG;
! 145: fp->conf.maxterminate = FSM_MAXTERMINATE;
! 146: fp->conf.maxfailure = FSM_MAXFAILURE;
! 147: fp->conf.check_magic = FALSE;
! 148: fp->conf.passive = FALSE;
! 149: fp->state = ST_INITIAL;
! 150: fp->reqid = 1;
! 151: fp->rejid = 1;
! 152: fp->echoid = 1;
! 153: }
! 154:
! 155: /*
! 156: * FsmInst()
! 157: *
! 158: * Instantiate FSM structure from template
! 159: */
! 160:
! 161: void
! 162: FsmInst(Fsm fp, Fsm fpt, void *arg)
! 163: {
! 164: memcpy(fp, fpt, sizeof(*fp));
! 165: fp->arg = arg;
! 166: }
! 167:
! 168: /*
! 169: * FsmNewState()
! 170: *
! 171: * Change state of a FSM. Also, call the configuration routine
! 172: * if this is an appropriate time.
! 173: */
! 174:
! 175: void
! 176: FsmNewState(Fsm fp, enum fsm_state new)
! 177: {
! 178: enum fsm_state old;
! 179:
! 180: /* Log it */
! 181: Log(fp->log2, ("[%s] %s: state change %s --> %s",
! 182: Pref(fp), Fsm(fp), FsmStateName(fp->state), FsmStateName(new)));
! 183:
! 184: /* Change state and call protocol's own handler, if any */
! 185: old = fp->state;
! 186: if (fp->type->NewState)
! 187: (*fp->type->NewState)(fp, old, new);
! 188: fp->state = new;
! 189: if ((new >= ST_INITIAL && new <= ST_STOPPED) || (new == ST_OPENED))
! 190: TimerStop(&fp->timer);
! 191:
! 192: /* Turn on/off keep-alive echo packets (if so configured) */
! 193: if (old == ST_OPENED)
! 194: TimerStop(&fp->echoTimer);
! 195: if (new == ST_OPENED && fp->conf.echo_int != 0) {
! 196: fp->quietCount = 0;
! 197: memset(&fp->idleStats, 0, sizeof(fp->idleStats));
! 198: TimerInit(&fp->echoTimer, "FsmKeepAlive",
! 199: fp->conf.echo_int * SECONDS, FsmEchoTimeout, fp);
! 200: TimerStartRecurring(&fp->echoTimer);
! 201: }
! 202: }
! 203:
! 204: /*
! 205: * FsmOutputMbuf()
! 206: *
! 207: * Send out a control packet with specified contents. Consumes the mbuf.
! 208: */
! 209:
! 210: void
! 211: FsmOutputMbuf(Fsm fp, u_int code, u_int id, Mbuf payload)
! 212: {
! 213: Bund b;
! 214: Mbuf bp;
! 215: struct fsmheader hdr;
! 216:
! 217: if (fp->type->link_layer)
! 218: b = ((Link)fp->arg)->bund;
! 219: else
! 220: b = (Bund)fp->arg;
! 221:
! 222: /* Build header */
! 223: hdr.id = id;
! 224: hdr.code = code;
! 225: hdr.length = htons(sizeof(hdr) + MBLEN(payload));
! 226:
! 227: /* Prepend to payload */
! 228: bp = mbcopyback(payload, -(int)sizeof(hdr), &hdr, sizeof(hdr));
! 229:
! 230: /* Send it out */
! 231: if (fp->type->link_layer) {
! 232: NgFuncWritePppFrameLink((Link)fp->arg, fp->type->proto, bp);
! 233: } else {
! 234: NgFuncWritePppFrame(b, NG_PPP_BUNDLE_LINKNUM, fp->type->proto, bp);
! 235: }
! 236: }
! 237:
! 238: /*
! 239: * FsmOutput()
! 240: *
! 241: * Send out a control packet with specified contents
! 242: */
! 243:
! 244: void
! 245: FsmOutput(Fsm fp, u_int code, u_int id, u_char *ptr, int len)
! 246: {
! 247: Mbuf bp;
! 248:
! 249: bp = (len > 0) ? mbcopyback(NULL, 0, ptr, len) : NULL;
! 250: FsmOutputMbuf(fp, code, id, bp);
! 251: }
! 252:
! 253: /*
! 254: * FsmOpen()
! 255: *
! 256: * XXX The use of the restart option should probably be
! 257: * XXX configured per FSM via the initialization structure.
! 258: * XXX For now, we just make it mandatory via #ifdef's.
! 259: */
! 260:
! 261: void
! 262: FsmOpen(Fsm fp)
! 263: {
! 264: Log(fp->log2, ("[%s] %s: Open event", Pref(fp), Fsm(fp)));
! 265: switch (fp->state) {
! 266: case ST_INITIAL:
! 267: FsmNewState(fp, ST_STARTING);
! 268: FsmLayerStart(fp);
! 269: break;
! 270: case ST_STARTING:
! 271: break;
! 272: case ST_CLOSED:
! 273: if (fp->type->Configure)
! 274: (*fp->type->Configure)(fp);
! 275: FsmNewState(fp, ST_REQSENT);
! 276: FsmLayerStart(fp); /* Missing in RFC 1661 */
! 277: FsmInitRestartCounter(fp, fp->conf.maxconfig);
! 278: FsmInitMaxFailure(fp, fp->conf.maxfailure);
! 279: FsmInitMaxConfig(fp, fp->conf.maxconfig);
! 280: FsmSendConfigReq(fp);
! 281: break;
! 282: case ST_REQSENT:
! 283: case ST_ACKRCVD:
! 284: case ST_ACKSENT:
! 285: break;
! 286:
! 287: case ST_OPENED:
! 288: #ifdef RESTART_OPENED
! 289: FsmDown(fp);
! 290: FsmUp(fp);
! 291: #endif
! 292: break;
! 293:
! 294: case ST_CLOSING:
! 295: FsmNewState(fp, ST_STOPPING);
! 296: case ST_STOPPING:
! 297: #ifdef RESTART_CLOSING
! 298: FsmDown(fp);
! 299: FsmUp(fp);
! 300: #endif
! 301: break;
! 302:
! 303: case ST_STOPPED:
! 304: #ifdef RESTART_STOPPED
! 305: FsmDown(fp);
! 306: FsmUp(fp);
! 307: #endif
! 308: break;
! 309: }
! 310: }
! 311:
! 312: void
! 313: FsmUp(Fsm fp)
! 314: {
! 315: Log(fp->log2, ("[%s] %s: Up event", Pref(fp), Fsm(fp)));
! 316: switch (fp->state) {
! 317: case ST_INITIAL:
! 318: FsmNewState(fp, ST_CLOSED);
! 319: break;
! 320: case ST_STARTING:
! 321: if (fp->type->Configure)
! 322: (*fp->type->Configure)(fp);
! 323: FsmNewState(fp, ST_REQSENT);
! 324: FsmInitRestartCounter(fp, fp->conf.maxconfig);
! 325: FsmInitMaxFailure(fp, fp->conf.maxfailure);
! 326: FsmInitMaxConfig(fp, fp->conf.maxconfig);
! 327: FsmSendConfigReq(fp);
! 328: break;
! 329: default:
! 330: Log(fp->log2, ("[%s] %s: Oops, UP at %s",
! 331: Pref(fp), Fsm(fp), FsmStateName(fp->state)));
! 332: break;
! 333: }
! 334: }
! 335:
! 336: void
! 337: FsmDown(Fsm fp)
! 338: {
! 339: Log(fp->log2, ("[%s] %s: Down event", Pref(fp), Fsm(fp)));
! 340: switch (fp->state) {
! 341: case ST_CLOSING:
! 342: FsmLayerFinish(fp); /* Missing in RFC 1661 */
! 343: /* fall through */
! 344: case ST_CLOSED:
! 345: FsmNewState(fp, ST_INITIAL);
! 346: break;
! 347: case ST_STOPPED:
! 348: FsmNewState(fp, ST_STARTING);
! 349: FsmLayerStart(fp);
! 350: break;
! 351: case ST_STOPPING:
! 352: case ST_REQSENT:
! 353: case ST_ACKRCVD:
! 354: case ST_ACKSENT:
! 355: FsmNewState(fp, ST_STARTING);
! 356: if (fp->type->UnConfigure)
! 357: (*fp->type->UnConfigure)(fp);
! 358: break;
! 359: case ST_OPENED:
! 360: FsmNewState(fp, ST_STARTING);
! 361: FsmLayerDown(fp);
! 362: if (fp->type->UnConfigure)
! 363: (*fp->type->UnConfigure)(fp);
! 364: break;
! 365: default:
! 366: break;
! 367: }
! 368: }
! 369:
! 370: void
! 371: FsmClose(Fsm fp)
! 372: {
! 373: Log(fp->log2, ("[%s] %s: Close event", Pref(fp), Fsm(fp)));
! 374: switch (fp->state) {
! 375: case ST_STARTING:
! 376: FsmNewState(fp, ST_INITIAL);
! 377: FsmLayerFinish(fp);
! 378: break;
! 379: case ST_STOPPED:
! 380: FsmNewState(fp, ST_CLOSED);
! 381: break;
! 382: case ST_STOPPING:
! 383: FsmNewState(fp, ST_CLOSING);
! 384: break;
! 385: case ST_OPENED:
! 386: FsmNewState(fp, ST_CLOSING);
! 387: FsmInitRestartCounter(fp, fp->conf.maxterminate);
! 388: FsmSendTerminateReq(fp);
! 389: FsmLayerDown(fp);
! 390: if (fp->type->UnConfigure)
! 391: (*fp->type->UnConfigure)(fp);
! 392: break;
! 393: case ST_REQSENT:
! 394: case ST_ACKRCVD:
! 395: case ST_ACKSENT:
! 396: FsmNewState(fp, ST_CLOSING);
! 397: FsmInitRestartCounter(fp, fp->conf.maxterminate);
! 398: FsmSendTerminateReq(fp);
! 399: if (fp->type->UnConfigure)
! 400: (*fp->type->UnConfigure)(fp);
! 401: break;
! 402: default:
! 403: break;
! 404: }
! 405: }
! 406:
! 407: /*
! 408: * Send functions
! 409: */
! 410:
! 411: static void
! 412: FsmSendConfigReq(Fsm fp)
! 413: {
! 414: u_char reqBuf[REQ_BUFFER_SIZE];
! 415: u_char *cp;
! 416:
! 417: /* Build and display config request */
! 418: Log(fp->log, ("[%s] %s: SendConfigReq #%d", Pref(fp), Fsm(fp), fp->reqid));
! 419: cp = (*fp->type->BuildConfigReq)(fp, reqBuf);
! 420: FsmDecodeBuffer(fp, reqBuf, cp - reqBuf, MODE_NOP);
! 421:
! 422: /* Send it */
! 423: FsmOutput(fp, CODE_CONFIGREQ, fp->reqid++, reqBuf, cp - reqBuf);
! 424:
! 425: /* Restart restart timer and decrement restart counter */
! 426: TimerStart(&fp->timer);
! 427: fp->restart--;
! 428: fp->config--;
! 429: }
! 430:
! 431: static void
! 432: FsmSendTerminateReq(Fsm fp)
! 433: {
! 434: Log(fp->log, ("[%s] %s: SendTerminateReq #%d", Pref(fp), Fsm(fp), fp->reqid));
! 435: FsmOutput(fp, CODE_TERMREQ, fp->reqid++, NULL, 0);
! 436: if (fp->type->SendTerminateReq)
! 437: (*fp->type->SendTerminateReq)(fp);
! 438: TimerStart(&fp->timer); /* Restart restart timer */
! 439: fp->restart--; /* Decrement restart counter */
! 440: }
! 441:
! 442: static void
! 443: FsmSendTerminateAck(Fsm fp)
! 444: {
! 445: Log(fp->log, ("[%s] %s: SendTerminateAck #%d", Pref(fp), Fsm(fp), fp->reqid));
! 446: FsmOutput(fp, CODE_TERMACK, fp->reqid++, NULL, 0);
! 447: if (fp->type->SendTerminateAck)
! 448: (*fp->type->SendTerminateAck)(fp);
! 449: }
! 450:
! 451: static void
! 452: FsmSendConfigAck(Fsm fp, FsmHeader lhp, u_char *option, int count)
! 453: {
! 454: Log(fp->log, ("[%s] %s: SendConfigAck #%d", Pref(fp), Fsm(fp), lhp->id));
! 455: FsmDecodeBuffer(fp, option, count, MODE_NOP);
! 456: FsmOutput(fp, CODE_CONFIGACK, lhp->id, option, count);
! 457: }
! 458:
! 459: static void
! 460: FsmSendConfigRej(Fsm fp, FsmHeader lhp, u_char *option, int count)
! 461: {
! 462: Log(fp->log, ("[%s] %s: SendConfigRej #%d", Pref(fp), Fsm(fp), lhp->id));
! 463: FsmDecodeBuffer(fp, option, count, MODE_NOP);
! 464: FsmOutput(fp, CODE_CONFIGREJ, lhp->id, option, count);
! 465: fp->failure--;
! 466: }
! 467:
! 468: static void
! 469: FsmSendConfigNak(Fsm fp, FsmHeader lhp, u_char *option, int count)
! 470: {
! 471: Log(fp->log, ("[%s] %s: SendConfigNak #%d", Pref(fp), Fsm(fp), lhp->id));
! 472: FsmDecodeBuffer(fp, option, count, MODE_NOP);
! 473: FsmOutput(fp, CODE_CONFIGNAK, lhp->id, option, count);
! 474: fp->failure--;
! 475: }
! 476:
! 477: /*
! 478: * Timeout actions
! 479: */
! 480:
! 481: static void
! 482: FsmTimeout(void *arg)
! 483: {
! 484: Fsm fp = (Fsm) arg;
! 485:
! 486: if (fp->restart > 0) { /* TO+ */
! 487: switch (fp->state) {
! 488: case ST_CLOSING:
! 489: case ST_STOPPING:
! 490: FsmSendTerminateReq(fp);
! 491: break;
! 492: case ST_REQSENT:
! 493: case ST_ACKSENT:
! 494: FsmSendConfigReq(fp);
! 495: break;
! 496: case ST_ACKRCVD:
! 497: FsmNewState(fp, ST_REQSENT);
! 498: FsmSendConfigReq(fp);
! 499: break;
! 500: default:
! 501: break;
! 502: }
! 503: } else { /* TO- */
! 504: switch (fp->state) {
! 505: case ST_CLOSING:
! 506: FsmNewState(fp, ST_CLOSED);
! 507: FsmLayerFinish(fp);
! 508: break;
! 509: case ST_STOPPING:
! 510: FsmNewState(fp, ST_STOPPED);
! 511: FsmLayerFinish(fp);
! 512: break;
! 513: case ST_REQSENT:
! 514: case ST_ACKSENT:
! 515: case ST_ACKRCVD:
! 516: FsmFailure(fp, FAIL_NEGOT_FAILURE);
! 517: break;
! 518: default:
! 519: break;
! 520: }
! 521: }
! 522: }
! 523:
! 524: void
! 525: FsmInitRestartCounter(Fsm fp, int value)
! 526: {
! 527: const int retry = fp->type->link_layer ?
! 528: ((Link)(fp->arg))->conf.retry_timeout :
! 529: ((Bund)(fp->arg))->conf.retry_timeout;
! 530:
! 531: TimerStop(&fp->timer);
! 532: TimerInit(&fp->timer,
! 533: fp->type->name, retry * SECONDS, FsmTimeout, (void *) fp);
! 534: fp->restart = value;
! 535: }
! 536:
! 537: void
! 538: FsmInitMaxFailure(Fsm fp, int value)
! 539: {
! 540: fp->failure = value;
! 541: }
! 542:
! 543: void
! 544: FsmInitMaxConfig(Fsm fp, int value)
! 545: {
! 546: fp->config = value;
! 547: }
! 548:
! 549: /*
! 550: * Actions that happen when we receive packets
! 551: */
! 552:
! 553: /* RCR */
! 554:
! 555: static void
! 556: FsmRecvConfigReq(Fsm fp, FsmHeader lhp, Mbuf bp)
! 557: {
! 558: int fullyAcked;
! 559:
! 560: /* Check and process easy cases */
! 561: switch (fp->state) {
! 562: case ST_INITIAL:
! 563: case ST_STARTING:
! 564: Log(fp->log2, ("[%s] %s: Oops, RCR in %s", Pref(fp), Fsm(fp), FsmStateName(fp->state)));
! 565: mbfree(bp);
! 566: return;
! 567: case ST_CLOSED:
! 568: FsmSendTerminateAck(fp);
! 569: mbfree(bp);
! 570: return;
! 571: case ST_STOPPED:
! 572: if (fp->type->Configure)
! 573: (*fp->type->Configure)(fp);
! 574: break;
! 575: case ST_CLOSING:
! 576: case ST_STOPPING:
! 577: mbfree(bp);
! 578: return;
! 579: default:
! 580: break;
! 581: }
! 582:
! 583: /* Decode packet */
! 584: FsmDecodeBuffer(fp, MBDATA(bp), MBLEN(bp), MODE_REQ);
! 585:
! 586: /* State specific actions */
! 587: switch (fp->state) {
! 588: case ST_OPENED:
! 589: FsmLayerDown(fp);
! 590: FsmSendConfigReq(fp);
! 591: break;
! 592: case ST_STOPPED:
! 593: FsmLayerStart(fp); /* Missing in RFC 1661 */
! 594: FsmInitRestartCounter(fp, fp->conf.maxconfig);
! 595: FsmInitMaxFailure(fp, fp->conf.maxfailure);
! 596: FsmInitMaxConfig(fp, fp->conf.maxconfig);
! 597: FsmSendConfigReq(fp);
! 598: break;
! 599: default:
! 600: break;
! 601: }
! 602:
! 603: /* What did we think of packet? */
! 604: fullyAcked = (gNakSize == 0 && gRejSize == 0);
! 605: if (fullyAcked)
! 606: FsmSendConfigAck(fp, lhp, gAckBuf, gAckSize);
! 607: else {
! 608: if (fp->failure <= 0) {
! 609: Log(fp->log, ("[%s] %s: not converging", Pref(fp), Fsm(fp)));
! 610: FsmFailure(fp, FAIL_NEGOT_FAILURE);
! 611: mbfree(bp);
! 612: return;
! 613: } else {
! 614: if (gRejSize)
! 615: FsmSendConfigRej(fp, lhp, gRejBuf, gRejSize);
! 616: else if (gNakSize)
! 617: FsmSendConfigNak(fp, lhp, gNakBuf, gNakSize);
! 618: }
! 619: }
! 620:
! 621: /* Continue with state transition */
! 622: switch (fp->state) {
! 623: case ST_STOPPED:
! 624: case ST_OPENED:
! 625: if (fullyAcked)
! 626: FsmNewState(fp, ST_ACKSENT);
! 627: else
! 628: FsmNewState(fp, ST_REQSENT);
! 629: break;
! 630: case ST_REQSENT:
! 631: if (fullyAcked)
! 632: FsmNewState(fp, ST_ACKSENT);
! 633: break;
! 634: case ST_ACKRCVD:
! 635: if (fullyAcked)
! 636: {
! 637: FsmNewState(fp, ST_OPENED);
! 638: FsmLayerUp(fp);
! 639: }
! 640: break;
! 641: case ST_ACKSENT:
! 642: if (!fullyAcked)
! 643: FsmNewState(fp, ST_REQSENT);
! 644: break;
! 645: default:
! 646: break;
! 647: }
! 648: mbfree(bp);
! 649: }
! 650:
! 651: /* RCA */
! 652:
! 653: static void
! 654: FsmRecvConfigAck(Fsm fp, FsmHeader lhp, Mbuf bp)
! 655: {
! 656:
! 657: /* Check sequence number */
! 658: if (lhp->id != (u_char) (fp->reqid - 1)) {
! 659: Log(fp->log, ("[%s] Wrong id#, expecting %d", Pref(fp), (u_char) (fp->reqid - 1)));
! 660: mbfree(bp);
! 661: return;
! 662: }
! 663:
! 664: /* XXX We should verify the contents are equal to our last sent config-req */
! 665:
! 666: /* Decode packet */
! 667: FsmDecodeBuffer(fp, MBDATA(bp), MBLEN(bp), MODE_NOP);
! 668:
! 669: /* Do whatever */
! 670: switch (fp->state) {
! 671: case ST_CLOSED:
! 672: case ST_STOPPED:
! 673: FsmSendTerminateAck(fp);
! 674: break;
! 675: case ST_CLOSING:
! 676: case ST_STOPPING:
! 677: break;
! 678: case ST_REQSENT:
! 679: FsmNewState(fp, ST_ACKRCVD);
! 680: FsmInitRestartCounter(fp, fp->conf.maxconfig);
! 681: FsmInitMaxFailure(fp, fp->conf.maxfailure);
! 682: FsmInitMaxConfig(fp, fp->conf.maxconfig);
! 683: TimerStart(&fp->timer); /* Start restart timer */
! 684: break;
! 685: case ST_ACKRCVD:
! 686: FsmNewState(fp, ST_REQSENT);
! 687: FsmSendConfigReq(fp);
! 688: break;
! 689: case ST_ACKSENT:
! 690: FsmNewState(fp, ST_OPENED);
! 691: FsmInitRestartCounter(fp, fp->conf.maxconfig);
! 692: FsmInitMaxFailure(fp, fp->conf.maxfailure);
! 693: FsmInitMaxConfig(fp, fp->conf.maxconfig);
! 694: FsmLayerUp(fp);
! 695: break;
! 696: case ST_OPENED:
! 697: FsmNewState(fp, ST_REQSENT);
! 698: FsmLayerDown(fp);
! 699: FsmSendConfigReq(fp);
! 700: break;
! 701: default:
! 702: break;
! 703: }
! 704: mbfree(bp);
! 705: }
! 706:
! 707: /* RCN */
! 708:
! 709: static void
! 710: FsmRecvConfigNak(Fsm fp, FsmHeader lhp, Mbuf bp)
! 711: {
! 712:
! 713: /* Check sequence number */
! 714: if (lhp->id != (u_char) (fp->reqid - 1)) {
! 715: Log(fp->log, ("[%s] Wrong id#, expecting %d", Pref(fp), (u_char) (fp->reqid - 1)));
! 716: mbfree(bp);
! 717: return;
! 718: }
! 719:
! 720: /* Check and process easy cases */
! 721: switch (fp->state) {
! 722: case ST_INITIAL:
! 723: case ST_STARTING:
! 724: Log(fp->log, ("[%s] %s: Oops, RCN in %s", Pref(fp), Fsm(fp), FsmStateName(fp->state)));
! 725: mbfree(bp);
! 726: return;
! 727: case ST_CLOSED:
! 728: case ST_STOPPED:
! 729: FsmSendTerminateAck(fp);
! 730: mbfree(bp);
! 731: return;
! 732: case ST_CLOSING:
! 733: case ST_STOPPING:
! 734: mbfree(bp);
! 735: return;
! 736: default:
! 737: break;
! 738: }
! 739:
! 740: /* Decode packet */
! 741: FsmDecodeBuffer(fp, MBDATA(bp), MBLEN(bp), MODE_NAK);
! 742:
! 743: /* Not converging? */
! 744: if (fp->config <= 0) {
! 745: Log(fp->log, ("[%s] %s: not converging", Pref(fp), Fsm(fp)));
! 746: FsmFailure(fp, FAIL_NEGOT_FAILURE);
! 747: mbfree(bp);
! 748: return;
! 749: }
! 750:
! 751: /* Do whatever */
! 752: switch (fp->state) {
! 753: case ST_REQSENT:
! 754: case ST_ACKSENT:
! 755: FsmInitRestartCounter(fp, fp->conf.maxconfig);
! 756: FsmSendConfigReq(fp);
! 757: break;
! 758: case ST_OPENED:
! 759: FsmLayerDown(fp);
! 760: /* fall through */
! 761: case ST_ACKRCVD:
! 762: FsmNewState(fp, ST_REQSENT);
! 763: FsmSendConfigReq(fp);
! 764: break;
! 765: default:
! 766: break;
! 767: }
! 768: mbfree(bp);
! 769: }
! 770:
! 771: /* RCJ */
! 772:
! 773: static void
! 774: FsmRecvConfigRej(Fsm fp, FsmHeader lhp, Mbuf bp)
! 775: {
! 776:
! 777: /* Check sequence number */
! 778: if (lhp->id != (u_char) (fp->reqid - 1)) {
! 779: Log(fp->log, ("[%s] Wrong id#, expecting %d", Pref(fp), (u_char) (fp->reqid - 1)));
! 780: mbfree(bp);
! 781: return;
! 782: }
! 783:
! 784: /* XXX should verify contents are a subset of previously sent config-req */
! 785:
! 786: /* Check and process easy cases */
! 787: switch (fp->state) {
! 788: case ST_INITIAL:
! 789: case ST_STARTING:
! 790: Log(fp->log, ("[%s] %s: Oops, RCJ in %s", Pref(fp), Fsm(fp), FsmStateName(fp->state)));
! 791: mbfree(bp);
! 792: return;
! 793: case ST_CLOSED:
! 794: case ST_STOPPED:
! 795: FsmSendTerminateAck(fp);
! 796: mbfree(bp);
! 797: return;
! 798: case ST_CLOSING:
! 799: case ST_STOPPING:
! 800: mbfree(bp);
! 801: return;
! 802: default:
! 803: break;
! 804: }
! 805:
! 806: /* Decode packet */
! 807: FsmDecodeBuffer(fp, MBDATA(bp), MBLEN(bp), MODE_REJ);
! 808:
! 809: /* Not converging? */
! 810: if (fp->config <= 0) {
! 811: Log(fp->log, ("[%s] %s: not converging", Pref(fp), Fsm(fp)));
! 812: FsmFailure(fp, FAIL_NEGOT_FAILURE);
! 813: mbfree(bp);
! 814: return;
! 815: }
! 816:
! 817: /* Do whatever */
! 818: switch (fp->state) {
! 819: case ST_REQSENT:
! 820: case ST_ACKSENT:
! 821: FsmInitRestartCounter(fp, fp->conf.maxconfig);
! 822: FsmSendConfigReq(fp);
! 823: break;
! 824: case ST_OPENED:
! 825: FsmNewState(fp, ST_REQSENT);
! 826: FsmLayerDown(fp);
! 827: FsmSendConfigReq(fp);
! 828: break;
! 829: case ST_ACKRCVD:
! 830: FsmNewState(fp, ST_REQSENT);
! 831: FsmSendConfigReq(fp);
! 832: break;
! 833: default:
! 834: break;
! 835: }
! 836: mbfree(bp);
! 837: }
! 838:
! 839: /* RTR */
! 840:
! 841: static void
! 842: FsmRecvTermReq(Fsm fp, FsmHeader lhp, Mbuf bp)
! 843: {
! 844: if (fp->type->link_layer) {
! 845: RecordLinkUpDownReason(NULL, (Link)(fp->arg), 0, STR_PEER_DISC, NULL);
! 846: }
! 847: switch (fp->state) {
! 848: case ST_INITIAL:
! 849: case ST_STARTING:
! 850: Log(fp->log, ("[%s] %s: Oops, RTR in %s", Pref(fp), Fsm(fp), FsmStateName(fp->state)));
! 851: break;
! 852: case ST_CLOSED:
! 853: case ST_STOPPED:
! 854: case ST_CLOSING:
! 855: case ST_STOPPING:
! 856: case ST_REQSENT:
! 857: FsmSendTerminateAck(fp);
! 858: break;
! 859: case ST_ACKRCVD:
! 860: case ST_ACKSENT:
! 861: FsmNewState(fp, ST_REQSENT);
! 862: FsmSendTerminateAck(fp);
! 863: break;
! 864: case ST_OPENED:
! 865: FsmNewState(fp, ST_STOPPING);
! 866: FsmSendTerminateAck(fp);
! 867: FsmLayerDown(fp);
! 868: FsmInitRestartCounter(fp, 0); /* Zero restart counter */
! 869: TimerStart(&fp->timer); /* Start restart timer */
! 870: if (fp->type->UnConfigure)
! 871: (*fp->type->UnConfigure)(fp);
! 872: break;
! 873: }
! 874: mbfree(bp);
! 875: }
! 876:
! 877: /* RTA */
! 878:
! 879: static void
! 880: FsmRecvTermAck(Fsm fp, FsmHeader lhp, Mbuf bp)
! 881: {
! 882: switch (fp->state) {
! 883: case ST_CLOSING:
! 884: FsmNewState(fp, ST_CLOSED);
! 885: FsmLayerFinish(fp);
! 886: break;
! 887: case ST_STOPPING:
! 888: FsmNewState(fp, ST_STOPPED);
! 889: FsmLayerFinish(fp);
! 890: break;
! 891: case ST_ACKRCVD:
! 892: FsmNewState(fp, ST_REQSENT);
! 893: break;
! 894: case ST_OPENED:
! 895: FsmNewState(fp, ST_REQSENT);
! 896: FsmLayerDown(fp);
! 897: FsmSendConfigReq(fp);
! 898: break;
! 899: default:
! 900: break;
! 901: }
! 902: mbfree(bp);
! 903: }
! 904:
! 905: /*
! 906: * FsmRecvCodeRej()
! 907: *
! 908: * By default, this is fatal for most codes
! 909: */
! 910:
! 911: static void
! 912: FsmRecvCodeRej(Fsm fp, FsmHeader lhp, Mbuf bp)
! 913: {
! 914: u_char code = 0;
! 915: int fatal;
! 916:
! 917: /* Get code and log it */
! 918: bp = mbread(bp, &code, sizeof(code));
! 919: Log(fp->log, ("[%s] %s: code %s was rejected", Pref(fp), Fsm(fp), FsmCodeName(code)));
! 920:
! 921: /* Determine fatalness */
! 922: if (fp->type->RecvCodeRej)
! 923: fatal = (*fp->type->RecvCodeRej)(fp, code, bp);
! 924: else {
! 925: switch (code) {
! 926: case CODE_CONFIGREQ:
! 927: case CODE_CONFIGACK:
! 928: case CODE_CONFIGNAK:
! 929: case CODE_CONFIGREJ:
! 930: case CODE_TERMREQ:
! 931: case CODE_TERMACK:
! 932: case CODE_CODEREJ:
! 933: case CODE_PROTOREJ:
! 934: case CODE_ECHOREQ:
! 935: case CODE_ECHOREP:
! 936: case CODE_RESETREQ:
! 937: case CODE_RESETACK:
! 938: fatal = TRUE;
! 939: break;
! 940: case CODE_VENDOR:
! 941: case CODE_DISCREQ:
! 942: case CODE_IDENT:
! 943: case CODE_TIMEREM:
! 944: default: /* if we don't know it, that makes two of us */
! 945: fatal = FALSE;
! 946: break;
! 947: }
! 948: }
! 949:
! 950: /* Possibly shut down as a result */
! 951: if (fatal)
! 952: FsmFailure(fp, FAIL_RECD_CODEREJ); /* RXJ- */
! 953: else
! 954: FsmRecvRxjPlus(fp);
! 955: mbfree(bp);
! 956: }
! 957:
! 958: /*
! 959: * FsmRecvProtoRej()
! 960: *
! 961: * By default, this is non-fatal
! 962: */
! 963:
! 964: static void
! 965: FsmRecvProtoRej(Fsm fp, FsmHeader lhp, Mbuf bp)
! 966: {
! 967: u_short proto = 0;
! 968: int fatal = FALSE;
! 969:
! 970: bp = mbread(bp, &proto, sizeof(proto));
! 971: proto = ntohs(proto);
! 972: Log(fp->log, ("[%s] %s: protocol %s was rejected", Pref(fp), Fsm(fp), ProtoName(proto)));
! 973: if (fp->state == ST_OPENED && fp->type->RecvProtoRej)
! 974: fatal = (*fp->type->RecvProtoRej)(fp, proto, bp);
! 975: if (fatal)
! 976: FsmFailure(fp, FAIL_RECD_PROTREJ); /* RXJ- */
! 977: else
! 978: FsmRecvRxjPlus(fp);
! 979: mbfree(bp);
! 980: }
! 981:
! 982: /*
! 983: * FsmRecvRxjPlus()
! 984: */
! 985:
! 986: static void
! 987: FsmRecvRxjPlus(Fsm fp) /* RXJ+ */
! 988: {
! 989: switch (fp->state) {
! 990: case ST_ACKRCVD:
! 991: FsmNewState(fp, ST_REQSENT);
! 992: break;
! 993: default:
! 994: break;
! 995: }
! 996: }
! 997:
! 998: /*
! 999: * FsmFailure()
! 1000: *
! 1001: * Call this at any point if something fatal happens that is inherent
! 1002: * to the FSM itself, like a RXJ- event or negotiation failed to converge.
! 1003: * The action taken is like the RXJ- event.
! 1004: */
! 1005:
! 1006: void
! 1007: FsmFailure(Fsm fp, enum fsmfail reason)
! 1008: {
! 1009: Log(fp->log, ("[%s] %s: %s", Pref(fp), Fsm(fp), FsmFailureStr(reason)));
! 1010:
! 1011: /* Let layer do any special handling of error code */
! 1012: if (fp->type->Failure)
! 1013: (*fp->type->Failure)(fp, reason);
! 1014:
! 1015: /* Shut this state machine down */
! 1016: switch (fp->state) {
! 1017: case ST_CLOSING:
! 1018: FsmNewState(fp, ST_CLOSED);
! 1019: /* fall through */
! 1020: case ST_CLOSED:
! 1021: FsmLayerFinish(fp);
! 1022: break;
! 1023: case ST_STOPPING:
! 1024: FsmNewState(fp, ST_STOPPED);
! 1025: FsmLayerFinish(fp);
! 1026: break;
! 1027: case ST_ACKRCVD:
! 1028: case ST_ACKSENT:
! 1029: case ST_REQSENT:
! 1030: FsmNewState(fp, ST_STOPPED);
! 1031: if (!fp->conf.passive)
! 1032: FsmLayerFinish(fp);
! 1033: if (fp->type->UnConfigure)
! 1034: (*fp->type->UnConfigure)(fp);
! 1035: break;
! 1036:
! 1037: /*
! 1038: * In the opened state, the peer FSM has somehow died or did something
! 1039: * horribly wrong to us. So the common sense action in this case is to
! 1040: * bring the whole link down, rather than restarting just the FSM.
! 1041: * We do this by telling the lower layer to restart using tlf and tls
! 1042: * while also pretending that we got a DOWN event.
! 1043: */
! 1044: case ST_OPENED:
! 1045: FsmNewState(fp, ST_STOPPING);
! 1046: FsmInitRestartCounter(fp, fp->conf.maxterminate);
! 1047: FsmSendTerminateReq(fp);
! 1048: FsmLayerDown(fp);
! 1049: if (fp->type->UnConfigure)
! 1050: (*fp->type->UnConfigure)(fp);
! 1051: break;
! 1052:
! 1053: /*
! 1054: * In the STOPPED state, then most likely the negotiation timed out
! 1055: * or didn't converge. Just wait for the DOWN event from the previously
! 1056: * issued tlf action.
! 1057: */
! 1058: case ST_STOPPED:
! 1059: if (!fp->conf.passive)
! 1060: FsmLayerFinish(fp);
! 1061: break;
! 1062: default:
! 1063: break;
! 1064: }
! 1065: }
! 1066:
! 1067: /*
! 1068: * FsmFailureStr()
! 1069: */
! 1070:
! 1071: const char *
! 1072: FsmFailureStr(enum fsmfail reason)
! 1073: {
! 1074: const char *string = NULL;
! 1075:
! 1076: switch (reason) {
! 1077: case FAIL_NEGOT_FAILURE:
! 1078: string = STR_FAIL_NEGOT_FAILURE;
! 1079: break;
! 1080: case FAIL_RECD_BADMAGIC:
! 1081: string = STR_FAIL_RECD_BADMAGIC;
! 1082: break;
! 1083: case FAIL_RECD_CODEREJ:
! 1084: string = STR_FAIL_RECD_CODEREJ;
! 1085: break;
! 1086: case FAIL_RECD_PROTREJ:
! 1087: string = STR_FAIL_RECD_PROTREJ;
! 1088: break;
! 1089: case FAIL_WAS_PROTREJ:
! 1090: string = STR_FAIL_WAS_PROTREJ;
! 1091: break;
! 1092: case FAIL_ECHO_TIMEOUT:
! 1093: string = STR_FAIL_ECHO_TIMEOUT;
! 1094: break;
! 1095: case FAIL_CANT_ENCRYPT:
! 1096: string = STR_FAIL_CANT_ENCRYPT;
! 1097: break;
! 1098: default:
! 1099: assert(0);
! 1100: }
! 1101: return(string);
! 1102: }
! 1103:
! 1104: /*
! 1105: * FsmSendEchoReq()
! 1106: *
! 1107: * Send an echo request containing the supplied payload data.
! 1108: * Consumes the mbuf.
! 1109: */
! 1110:
! 1111: void
! 1112: FsmSendEchoReq(Fsm fp, Mbuf payload)
! 1113: {
! 1114: u_int32_t const self_magic = htonl(((Link)(fp->arg))->lcp.want_magic);
! 1115: Mbuf bp;
! 1116:
! 1117: if (fp->state != ST_OPENED)
! 1118: return;
! 1119:
! 1120: /* Prepend my magic number */
! 1121: bp = mbcopyback(payload, -(int)sizeof(self_magic), &self_magic, sizeof(self_magic));
! 1122:
! 1123: /* Send it */
! 1124: Log(LG_ECHO, ("[%s] %s: SendEchoReq #%d", Pref(fp), Fsm(fp), fp->echoid));
! 1125: FsmOutputMbuf(fp, CODE_ECHOREQ, fp->echoid++, bp);
! 1126: }
! 1127:
! 1128: /*
! 1129: * FsmSendIdent()
! 1130: *
! 1131: * Send an LCP ident packet.
! 1132: */
! 1133:
! 1134: void
! 1135: FsmSendIdent(Fsm fp, const char *ident)
! 1136: {
! 1137: u_int32_t self_magic = htonl(((Link)(fp->arg))->lcp.want_magic);
! 1138: const int len = strlen(ident) + 1; /* include NUL to be nice */
! 1139: Mbuf bp;
! 1140:
! 1141: /* Leave magic zero unless fully opened, as IDENT can be sent anytime */
! 1142: if (fp->state != ST_OPENED)
! 1143: self_magic = 0;
! 1144:
! 1145: /* Prepend my magic number */
! 1146: bp = mbcopyback(NULL, 0, (u_char *) &self_magic, sizeof(self_magic));
! 1147: bp = mbcopyback(bp, sizeof(self_magic), ident, len);
! 1148:
! 1149: /* Send it */
! 1150: Log(LG_FSM, ("[%s] %s: SendIdent #%d", Pref(fp), Fsm(fp), fp->echoid));
! 1151: ShowMesg(LG_FSM, Pref(fp), ident, len);
! 1152: FsmOutputMbuf(fp, CODE_IDENT, fp->echoid++, bp);
! 1153: }
! 1154:
! 1155: /*
! 1156: * FsmSendTimeRemaining()
! 1157: *
! 1158: * Send an LCP Time-Remaining packet.
! 1159: */
! 1160:
! 1161: void
! 1162: FsmSendTimeRemaining(Fsm fp, u_int seconds)
! 1163: {
! 1164: u_int32_t self_magic = htonl(((Link)(fp->arg))->lcp.want_magic);
! 1165: u_int32_t data = htonl(seconds);
! 1166: Mbuf bp;
! 1167:
! 1168: /* Leave magic zero unless fully opened, as IDENT can be sent anytime */
! 1169: if (fp->state != ST_OPENED)
! 1170: self_magic = 0;
! 1171:
! 1172: /* Prepend my magic number */
! 1173: bp = mbcopyback(NULL, 0, (u_char *) &self_magic, sizeof(self_magic));
! 1174: bp = mbcopyback(bp, sizeof(self_magic), &data, 4);
! 1175:
! 1176: /* Send it */
! 1177: Log(LG_FSM, ("[%s] %s: SendTimeRemaining #%d", Pref(fp), Fsm(fp), fp->echoid));
! 1178: Log(LG_FSM, ("[%s] %u seconds remain", Pref(fp), seconds));
! 1179: FsmOutputMbuf(fp, CODE_TIMEREM, fp->echoid++, bp);
! 1180: }
! 1181:
! 1182: /*
! 1183: * FsmRecvEchoReq()
! 1184: */
! 1185:
! 1186: static void
! 1187: FsmRecvEchoReq(Fsm fp, FsmHeader lhp, Mbuf bp)
! 1188: {
! 1189: u_int32_t self_magic;
! 1190:
! 1191: /* Validate magic number */
! 1192: bp = FsmCheckMagic(fp, bp);
! 1193:
! 1194: /* If not opened, do nothing */
! 1195: if (fp->state != ST_OPENED) {
! 1196: mbfree(bp);
! 1197: return;
! 1198: }
! 1199:
! 1200: /* Stick my magic number in there instead */
! 1201: self_magic = htonl(((Link)(fp->arg))->lcp.want_magic);
! 1202: bp = mbcopyback(bp, -(int)sizeof(self_magic), &self_magic, sizeof(self_magic));
! 1203:
! 1204: /* Send it back, preserving everything else */
! 1205: Log(LG_ECHO, ("[%s] %s: SendEchoRep #%d", Pref(fp), Fsm(fp), lhp->id));
! 1206: FsmOutputMbuf(fp, CODE_ECHOREP, lhp->id, bp);
! 1207: }
! 1208:
! 1209: /*
! 1210: * FsmRecvEchoRep()
! 1211: */
! 1212:
! 1213: static void
! 1214: FsmRecvEchoRep(Fsm fp, FsmHeader lhp, Mbuf bp)
! 1215: {
! 1216: bp = FsmCheckMagic(fp, bp);
! 1217: mbfree(bp);
! 1218: }
! 1219:
! 1220: /*
! 1221: * FsmRecvDiscReq()
! 1222: */
! 1223:
! 1224: static void
! 1225: FsmRecvDiscReq(Fsm fp, FsmHeader lhp, Mbuf bp)
! 1226: {
! 1227: bp = FsmCheckMagic(fp, bp);
! 1228: if (fp->type->RecvDiscReq)
! 1229: (*fp->type->RecvDiscReq)(fp, bp);
! 1230: mbfree(bp);
! 1231: }
! 1232:
! 1233: /*
! 1234: * FsmRecvIdent()
! 1235: */
! 1236:
! 1237: static void
! 1238: FsmRecvIdent(Fsm fp, FsmHeader lhp, Mbuf bp)
! 1239: {
! 1240: bp = FsmCheckMagic(fp, bp);
! 1241: if (bp)
! 1242: ShowMesg(fp->log, Pref(fp), (char *) MBDATA(bp), MBLEN(bp));
! 1243: if (fp->type->RecvIdent)
! 1244: (*fp->type->RecvIdent)(fp, bp);
! 1245: mbfree(bp);
! 1246: }
! 1247:
! 1248: /*
! 1249: * FsmRecvVendor()
! 1250: */
! 1251:
! 1252: static void
! 1253: FsmRecvVendor(Fsm fp, FsmHeader lhp, Mbuf bp)
! 1254: {
! 1255: bp = FsmCheckMagic(fp, bp);
! 1256: if (fp->type->RecvVendor)
! 1257: (*fp->type->RecvVendor)(fp, bp);
! 1258: mbfree(bp);
! 1259: }
! 1260:
! 1261: /*
! 1262: * FsmRecvTimeRemain()
! 1263: */
! 1264:
! 1265: static void
! 1266: FsmRecvTimeRemain(Fsm fp, FsmHeader lhp, Mbuf bp)
! 1267: {
! 1268: bp = FsmCheckMagic(fp, bp);
! 1269: if (bp) {
! 1270: u_int32_t remain = 0;
! 1271: mbcopy(bp, 0, &remain, sizeof(remain));
! 1272: remain = ntohl(remain);
! 1273: Log(fp->log, ("[%s] %u seconds remain", Pref(fp), remain));
! 1274: }
! 1275: if (fp->type->RecvTimeRemain)
! 1276: (*fp->type->RecvTimeRemain)(fp, bp);
! 1277: mbfree(bp);
! 1278: }
! 1279:
! 1280: /*
! 1281: * FsmRecvResetReq()
! 1282: */
! 1283:
! 1284: static void
! 1285: FsmRecvResetReq(Fsm fp, FsmHeader lhp, Mbuf bp)
! 1286: {
! 1287: if (fp->type->RecvResetReq)
! 1288: (*fp->type->RecvResetReq)(fp, lhp->id, bp);
! 1289: mbfree(bp);
! 1290: }
! 1291:
! 1292: /*
! 1293: * FsmRecvResetAck()
! 1294: */
! 1295:
! 1296: static void
! 1297: FsmRecvResetAck(Fsm fp, FsmHeader lhp, Mbuf bp)
! 1298: {
! 1299: if (fp->type->RecvResetAck)
! 1300: (*fp->type->RecvResetAck)(fp, lhp->id, bp);
! 1301: mbfree(bp);
! 1302: }
! 1303:
! 1304: /*
! 1305: * FsmLayerUp()
! 1306: */
! 1307:
! 1308: static void
! 1309: FsmLayerUp(Fsm fp)
! 1310: {
! 1311: Log(fp->log2, ("[%s] %s: LayerUp", Pref(fp), Fsm(fp)));
! 1312: if (fp->type->LayerUp)
! 1313: (*fp->type->LayerUp)(fp);
! 1314: }
! 1315:
! 1316: /*
! 1317: * FsmLayerDown()
! 1318: */
! 1319:
! 1320: static void
! 1321: FsmLayerDown(Fsm fp)
! 1322: {
! 1323: Log(fp->log2, ("[%s] %s: LayerDown", Pref(fp), Fsm(fp)));
! 1324: if (fp->type->LayerDown)
! 1325: (*fp->type->LayerDown)(fp);
! 1326: }
! 1327:
! 1328: /*
! 1329: * FsmLayerStart()
! 1330: */
! 1331:
! 1332: static void
! 1333: FsmLayerStart(Fsm fp)
! 1334: {
! 1335: Log(fp->log2, ("[%s] %s: LayerStart", Pref(fp), Fsm(fp)));
! 1336: if (fp->type->LayerStart)
! 1337: (*fp->type->LayerStart)(fp);
! 1338: }
! 1339:
! 1340: /*
! 1341: * FsmLayerFinish()
! 1342: */
! 1343:
! 1344: static void
! 1345: FsmLayerFinish(Fsm fp)
! 1346: {
! 1347: Log(fp->log2, ("[%s] %s: LayerFinish", Pref(fp), Fsm(fp)));
! 1348: if (fp->type->LayerFinish)
! 1349: (*fp->type->LayerFinish)(fp);
! 1350: }
! 1351:
! 1352: /*
! 1353: * FsmCheckMagic()
! 1354: */
! 1355:
! 1356: static Mbuf
! 1357: FsmCheckMagic(Fsm fp, Mbuf bp)
! 1358: {
! 1359: u_int32_t peer_magic;
! 1360: u_int32_t peer_magic_ought;
! 1361:
! 1362: /* Read magic number */
! 1363: bp = mbread(bp, &peer_magic, sizeof(peer_magic));
! 1364: peer_magic = ntohl(peer_magic);
! 1365:
! 1366: /* What should magic number be? */
! 1367: if (PROT_LINK_LAYER(fp->type->proto))
! 1368: peer_magic_ought = ((Link)(fp->arg))->lcp.peer_magic;
! 1369: else
! 1370: peer_magic_ought = 0;
! 1371:
! 1372: /* Verify */
! 1373: if (fp->conf.check_magic && peer_magic != 0
! 1374: && peer_magic != peer_magic_ought) {
! 1375: Log(fp->log, ("[%s] %s: magic number is wrong: 0x%08x != 0x%08x",
! 1376: Pref(fp), Fsm(fp), peer_magic, peer_magic_ought));
! 1377: FsmFailure(fp, FAIL_RECD_BADMAGIC);
! 1378: }
! 1379: return(bp);
! 1380: }
! 1381:
! 1382: /*
! 1383: * FsmEchoTimeout()
! 1384: */
! 1385:
! 1386: static void
! 1387: FsmEchoTimeout(void *arg)
! 1388: {
! 1389: Fsm const fp = (Fsm) arg;
! 1390: Bund b;
! 1391: Link l;
! 1392: struct ng_ppp_link_stat oldStats;
! 1393:
! 1394: if (fp->type->link_layer) {
! 1395: l = (Link)fp->arg;
! 1396: b = l->bund;
! 1397: } else {
! 1398: b = (Bund)fp->arg;
! 1399: l = NULL;
! 1400: }
! 1401:
! 1402: if (!b) {
! 1403: /* We can't get link stat without bundle present */
! 1404: return;
! 1405: }
! 1406:
! 1407: /* See if there was any traffic since last time */
! 1408: oldStats = fp->idleStats;
! 1409: NgFuncGetStats(b, l ?
! 1410: l->bundleIndex : NG_PPP_BUNDLE_LINKNUM, &fp->idleStats);
! 1411: if (fp->idleStats.recvFrames > oldStats.recvFrames)
! 1412: fp->quietCount = 0;
! 1413: else
! 1414: fp->quietCount++;
! 1415:
! 1416: /* See if peer hasn't responded for too many requests */
! 1417: switch (fp->quietCount) {
! 1418:
! 1419: /* Peer failed to reply to previous echo request */
! 1420: default:
! 1421: Log(LG_ECHO|fp->log,
! 1422: ("[%s] %s: no reply to %d echo request(s)",
! 1423: Pref(fp), Fsm(fp), fp->quietCount - 1));
! 1424:
! 1425: /* Has peer failed to reply for maximum allowable interval? */
! 1426: if (fp->quietCount * fp->conf.echo_int >= fp->conf.echo_max) {
! 1427: TimerStop(&fp->echoTimer);
! 1428: FsmFailure(fp, FAIL_ECHO_TIMEOUT);
! 1429: break;
! 1430: }
! 1431: /* fall through */
! 1432: case 1: /* one interval of silence elapsed; send first echo request */
! 1433: FsmSendEchoReq(fp, NULL);
! 1434: /* fall through */
! 1435: case 0:
! 1436: break;
! 1437: }
! 1438: }
! 1439:
! 1440: /*
! 1441: * FsmInput()
! 1442: *
! 1443: * Deal with an incoming packet for FSM pointed to by "fp"
! 1444: */
! 1445:
! 1446: void
! 1447: FsmInput(Fsm fp, Mbuf bp)
! 1448: {
! 1449: int log, recd_len, length;
! 1450: struct fsmheader hdr;
! 1451:
! 1452: /* Check for runt frames; discard them */
! 1453: if ((recd_len = MBLEN(bp)) < sizeof(hdr)) {
! 1454: Log(fp->log, ("[%s] %s: runt packet: %d bytes", Pref(fp), Fsm(fp), recd_len));
! 1455: mbfree(bp);
! 1456: return;
! 1457: }
! 1458:
! 1459: /* Read in the header */
! 1460: bp = mbread(bp, &hdr, sizeof(hdr));
! 1461: length = ntohs(hdr.length);
! 1462:
! 1463: /* Make sure length is sensible; discard otherwise */
! 1464: if (length < sizeof(hdr) || length > recd_len) {
! 1465: Log(fp->log, ("[%s] %s: bad length: says %d, rec'd %d",
! 1466: Pref(fp), Fsm(fp), length, recd_len));
! 1467: mbfree(bp);
! 1468: return;
! 1469: }
! 1470:
! 1471: /* Truncate off any padding bytes */
! 1472: if (length < recd_len)
! 1473: bp = mbtrunc(bp, length - sizeof(hdr));
! 1474:
! 1475: /* Check for a valid code byte -- if not, send code-reject */
! 1476: if ((hdr.code >= NUM_FSM_CODES) ||
! 1477: (((1 << hdr.code) & fp->type->known_codes) == 0)) { /* RUC */
! 1478: Log(fp->log, ("[%s] %s: unknown code %d", Pref(fp), Fsm(fp), hdr.code));
! 1479: FsmOutputMbuf(fp, CODE_CODEREJ, fp->rejid++, bp);
! 1480: return;
! 1481: }
! 1482:
! 1483: /* Log it */
! 1484: if (hdr.code == CODE_ECHOREQ || hdr.code == CODE_ECHOREP)
! 1485: log = LG_ECHO;
! 1486: else if (hdr.code == CODE_RESETREQ || hdr.code == CODE_RESETACK)
! 1487: log = fp->log2;
! 1488: else
! 1489: log = fp->log;
! 1490: Log(log, ("[%s] %s: rec'd %s #%d (%s)",
! 1491: Pref(fp), Fsm(fp), FsmCodeName(hdr.code), (int) hdr.id,
! 1492: FsmStateName(fp->state)));
! 1493:
! 1494: /* Do whatever */
! 1495: (*FsmCodes[hdr.code].action)(fp, &hdr, bp);
! 1496: }
! 1497:
! 1498: /*
! 1499: * FsmConfValue()
! 1500: *
! 1501: * Write in a configuration item with "len" bytes of information.
! 1502: * Special cases: length -2 or -4 means convert to network byte order.
! 1503: */
! 1504:
! 1505: u_char *
! 1506: FsmConfValue(u_char *cp, int type, int len, const void *data)
! 1507: {
! 1508: u_char *bytes = (u_char *) data;
! 1509: u_int16_t sv;
! 1510: u_int32_t lv;
! 1511:
! 1512: /* Special cases */
! 1513: switch (len) {
! 1514: case -2:
! 1515: len = 2;
! 1516: sv = htons(*((u_int16_t *) data));
! 1517: bytes = (u_char *) &sv;
! 1518: break;
! 1519: case -4:
! 1520: len = 4;
! 1521: lv = htonl(*((u_int32_t *) data));
! 1522: bytes = (u_char *) &lv;
! 1523: break;
! 1524: default:
! 1525: break;
! 1526: }
! 1527:
! 1528: /* Add header and data */
! 1529: *cp++ = type;
! 1530: *cp++ = len + 2;
! 1531: while (len-- > 0)
! 1532: *cp++ = *bytes++;
! 1533:
! 1534: /* Done */
! 1535: return(cp);
! 1536: }
! 1537:
! 1538: /*
! 1539: * FsmExtractOptions()
! 1540: *
! 1541: * Extract options from a config packet
! 1542: */
! 1543:
! 1544: static int
! 1545: FsmExtractOptions(Fsm fp, u_char *data, int dlen, FsmOption opts, int max)
! 1546: {
! 1547: int num;
! 1548:
! 1549: for (num = 0; dlen >= 2 && num < max; num++) {
! 1550: FsmOption const opt = &opts[num];
! 1551:
! 1552: opt->type = data[0];
! 1553: opt->len = data[1];
! 1554: opt->data = &data[2];
! 1555: if (opt->len < 2 || opt->len > dlen)
! 1556: break;
! 1557: data += opt->len;
! 1558: dlen -= opt->len;
! 1559: }
! 1560: if (dlen != 0)
! 1561: LogDumpBuf(LG_ERR, data, dlen,
! 1562: "[%s] %s: %d extra garbage bytes in config packet", Pref(fp), Fsm(fp), dlen);
! 1563: return(num);
! 1564: }
! 1565:
! 1566: /*
! 1567: * FsmFindOption()
! 1568: */
! 1569:
! 1570: FsmOptInfo
! 1571: FsmFindOptInfo(FsmOptInfo list, u_char type)
! 1572: {
! 1573: for (; list->name; list++)
! 1574: if (list->type == type)
! 1575: return(list);
! 1576: return(NULL);
! 1577: }
! 1578:
! 1579: /*
! 1580: * FsmDecodeBuffer()
! 1581: */
! 1582:
! 1583: static void
! 1584: FsmDecodeBuffer(Fsm fp, u_char *buf, int size, int mode)
! 1585: {
! 1586: struct fsmoption opts[FSM_MAX_OPTS];
! 1587: int num;
! 1588:
! 1589: if (mode == MODE_REQ)
! 1590: gAckSize = gNakSize = gRejSize = 0;
! 1591: num = FsmExtractOptions(fp, buf, size, opts, FSM_MAX_OPTS);
! 1592: (*fp->type->DecodeConfig)(fp, opts, num, mode);
! 1593: }
! 1594:
! 1595: /*
! 1596: * FsmAck()
! 1597: */
! 1598:
! 1599: void
! 1600: FsmAck(Fsm fp, const struct fsmoption *opt)
! 1601: {
! 1602: if (gAckSize + opt->len > sizeof(gAckBuf)) {
! 1603: Log(LG_ERR, ("[%s] %s: %s buffer full", Pref(fp), Fsm(fp), "ack"));
! 1604: return;
! 1605: }
! 1606: memcpy(&gAckBuf[gAckSize], opt, 2);
! 1607: memcpy(&gAckBuf[gAckSize + 2], opt->data, opt->len - 2);
! 1608: gAckSize += opt->len;
! 1609: }
! 1610:
! 1611: /*
! 1612: * FsmNak()
! 1613: */
! 1614:
! 1615: void
! 1616: FsmNak(Fsm fp, const struct fsmoption *opt)
! 1617: {
! 1618: if (gNakSize + opt->len > sizeof(gNakBuf)) {
! 1619: Log(LG_ERR, ("[%s] %s: %s buffer full", Pref(fp), Fsm(fp), "nak"));
! 1620: return;
! 1621: }
! 1622: memcpy(&gNakBuf[gNakSize], opt, 2);
! 1623: memcpy(&gNakBuf[gNakSize + 2], opt->data, opt->len - 2);
! 1624: gNakSize += opt->len;
! 1625: }
! 1626:
! 1627: /*
! 1628: * FsmRej()
! 1629: */
! 1630:
! 1631: void
! 1632: FsmRej(Fsm fp, const struct fsmoption *opt)
! 1633: {
! 1634: if (gRejSize + opt->len > sizeof(gRejBuf)) {
! 1635: Log(LG_ERR, ("[%s] %s: %s buffer full", Pref(fp), Fsm(fp), "rej"));
! 1636: return;
! 1637: }
! 1638: memcpy(&gRejBuf[gRejSize], opt, 2);
! 1639: memcpy(&gRejBuf[gRejSize + 2], opt->data, opt->len - 2);
! 1640: gRejSize += opt->len;
! 1641: }
! 1642:
! 1643: /*
! 1644: * FsmCodeName()
! 1645: */
! 1646:
! 1647: const char *
! 1648: FsmCodeName(int code)
! 1649: {
! 1650: if (code >= 0 && code < NUM_FSM_CODES)
! 1651: return (FsmCodes[code].name);
! 1652: return ("UNKNOWN");
! 1653: }
! 1654:
! 1655: /*
! 1656: * FsmStateName()
! 1657: */
! 1658:
! 1659: const char *
! 1660: FsmStateName(enum fsm_state state)
! 1661: {
! 1662: switch (state) {
! 1663: case ST_INITIAL: return "Initial";
! 1664: case ST_STARTING: return "Starting";
! 1665: case ST_CLOSED: return "Closed";
! 1666: case ST_STOPPED: return "Stopped";
! 1667: case ST_CLOSING: return "Closing";
! 1668: case ST_STOPPING: return "Stopping";
! 1669: case ST_REQSENT: return "Req-Sent";
! 1670: case ST_ACKRCVD: return "Ack-Rcvd";
! 1671: case ST_ACKSENT: return "Ack-Sent";
! 1672: case ST_OPENED: return "Opened";
! 1673: }
! 1674: return "???";
! 1675: }
! 1676:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>