From 21ef2761fd1e5a4beb483da8bddf767d36540dce Mon Sep 17 00:00:00 2001 From: amurai Date: Tue, 31 Jan 1995 06:29:58 +0000 Subject: --- usr.sbin/ppp/fsm.c | 802 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 802 insertions(+) create mode 100644 usr.sbin/ppp/fsm.c (limited to 'usr.sbin/ppp/fsm.c') diff --git a/usr.sbin/ppp/fsm.c b/usr.sbin/ppp/fsm.c new file mode 100644 index 0000000..89f9151 --- /dev/null +++ b/usr.sbin/ppp/fsm.c @@ -0,0 +1,802 @@ +/* + * PPP Finite State Machine for LCP/IPCP + * + * Written by Toshiharu OHNO (tony-o@iij.ad.jp) + * + * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the Internet Initiative Japan, Inc. The name of the + * IIJ may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * $Id:$ + * + * TODO: + * o Refer loglevel for log output + * o Better option log display + */ +#include "fsm.h" +#include "hdlc.h" +#include "lqr.h" +#include "lcpproto.h" +#include "lcp.h" + +void FsmSendConfigReq(struct fsm *fp); +void FsmSendTerminateReq(struct fsm *fp); +void FsmInitRestartCounter(struct fsm *fp); +void FsmTimeout(struct fsm *fp); + +char *StateNames[] = { + "Initial", "Starting", "Closed", "Stopped", "Closing", "Stopping", + "Req-Sent", "Ack-Rcvd", "Ack-Sent", "Opend", +}; + +void +FsmInit(fp) +struct fsm *fp; +{ +#ifdef DEBUG + logprintf("FsmInit\n"); +#endif + fp->state = ST_INITIAL; + fp->reqid = 1; + fp->restart = 1; + fp->maxconfig = 3; +} + +void +NewState(fp, new) +struct fsm *fp; +int new; +{ + LogPrintf(LOG_LCP, "%s: state change %s --> %s\n", + fp->name, StateNames[fp->state], StateNames[new]); + fp->state = new; + if ((new >= ST_INITIAL && new <= ST_STOPPED) || (new == ST_OPENED)) + StopTimer(&fp->FsmTimer); +} + +void +FsmOutput(fp, code, id, ptr, count) +struct fsm *fp; +u_int code, id; +u_char *ptr; +int count; +{ + int plen; + struct fsmheader lh; + struct mbuf *bp; + + plen = sizeof(struct fsmheader) + count; + lh.code = code; + lh.id = id; + lh.length = htons(plen); + bp = mballoc(plen, MB_FSM); + bcopy(&lh, MBUF_CTOP(bp), sizeof(struct fsmheader)); + if (count) + bcopy(ptr, MBUF_CTOP(bp) + sizeof(struct fsmheader), count); +#ifdef DEBUG + DumpBp(bp); +#endif + HdlcOutput(PRI_NORMAL, fp->proto, bp); +} + +void +FsmOpen(fp) +struct fsm *fp; +{ + switch (fp->state) { + case ST_INITIAL: + (fp->LayerStart)(fp); + NewState(fp, ST_STARTING); + break; + case ST_STARTING: + break; + case ST_CLOSED: + if (fp->open_mode == OPEN_PASSIVE) { + NewState(fp, ST_STOPPED); + } else { + FsmInitRestartCounter(fp); + FsmSendConfigReq(fp); + NewState(fp, ST_REQSENT); + } + break; + case ST_STOPPED: /* XXX: restart option */ + case ST_REQSENT: + case ST_ACKRCVD: + case ST_ACKSENT: + case ST_OPENED: /* XXX: restart option */ + break; + case ST_CLOSING: /* XXX: restart option */ + case ST_STOPPING: /* XXX: restart option */ + NewState(fp, ST_STOPPING); + break; + } +} + +void +FsmUp(fp) +struct fsm *fp; +{ + switch (fp->state) { + case ST_INITIAL: + NewState(fp, ST_CLOSED); + break; + case ST_STARTING: + FsmInitRestartCounter(fp); + FsmSendConfigReq(fp); + NewState(fp, ST_REQSENT); + break; + default: + LogPrintf(LOG_LCP, "%s: Oops, Up at %s\n", + fp->name, StateNames[fp->state]); + break; + } +} + +void +FsmDown(fp) +struct fsm *fp; +{ + switch (fp->state) { + case ST_CLOSED: + case ST_CLOSING: + NewState(fp, ST_INITIAL); + break; + case ST_STOPPED: + (fp->LayerStart)(fp); + /* Fall into.. */ + case ST_STOPPING: + case ST_REQSENT: + case ST_ACKRCVD: + case ST_ACKSENT: + NewState(fp, ST_STARTING); + break; + case ST_OPENED: + (fp->LayerDown)(fp); + NewState(fp, ST_STARTING); + break; + } +} + +void +FsmClose(fp) +struct fsm *fp; +{ + switch (fp->state) { + case ST_STARTING: + NewState(fp, ST_INITIAL); + break; + case ST_STOPPED: + NewState(fp, ST_CLOSED); + break; + case ST_STOPPING: + NewState(fp, ST_CLOSING); + break; + case ST_OPENED: + (fp->LayerDown)(fp); + /* Fall down */ + case ST_REQSENT: + case ST_ACKRCVD: + case ST_ACKSENT: + FsmInitRestartCounter(fp); + FsmSendTerminateReq(fp); + NewState(fp, ST_CLOSING); + break; + } +} + +/* + * Send functions + */ +void +FsmSendConfigReq(fp) +struct fsm *fp; +{ + if (--fp->maxconfig > 0) { + (fp->SendConfigReq)(fp); + StartTimer(&fp->FsmTimer); /* Start restart timer */ + fp->restart--; /* Decrement restart counter */ + } else { + FsmClose(fp); + } +} + +void +FsmSendTerminateReq(fp) +struct fsm *fp; +{ + LogPrintf(LOG_LCP, "%s: SendTerminateReq.\n", fp->name); + FsmOutput(fp, CODE_TERMREQ, fp->reqid++, NULL, 0); + (fp->SendTerminateReq)(fp); + StartTimer(&fp->FsmTimer); /* Start restart timer */ + fp->restart--; /* Decrement restart counter */ +} + +static void +FsmSendConfigAck(fp, lhp, option, count) +struct fsm *fp; +struct fsmheader *lhp; +u_char *option; +int count; +{ + LogPrintf(LOG_LCP, "%s: SendConfigAck(%s)\n", fp->name, StateNames[fp->state]); + FsmOutput(fp, CODE_CONFIGACK, lhp->id, option, count); +} + +static void +FsmSendConfigRej(fp, lhp, option, count) +struct fsm *fp; +struct fsmheader *lhp; +u_char *option; +int count; +{ + LogPrintf(LOG_LCP, "%s: SendConfigRej(%s)\n", fp->name, StateNames[fp->state]); + FsmOutput(fp, CODE_CONFIGREJ, lhp->id, option, count); +} + +static void +FsmSendConfigNak(fp, lhp, option, count) +struct fsm *fp; +struct fsmheader *lhp; +u_char *option; +int count; +{ + LogPrintf(LOG_LCP, "%s: SendConfigNak(%s)\n", + fp->name, StateNames[fp->state]); + FsmOutput(fp, CODE_CONFIGNAK, lhp->id, option, count); +} + +/* + * Timeout actions + */ +void +FsmTimeout(fp) +struct fsm *fp; +{ + if (fp->restart) { + switch (fp->state) { + case ST_CLOSING: + case ST_STOPPING: + FsmSendTerminateReq(fp); + break; + case ST_REQSENT: + case ST_ACKSENT: + FsmSendConfigReq(fp); + break; + case ST_ACKRCVD: + FsmSendConfigReq(fp); + NewState(fp, ST_REQSENT); + break; + } + StartTimer(&fp->FsmTimer); + } else { + switch (fp->state) { + case ST_CLOSING: + NewState(fp, ST_CLOSED); + (fp->LayerFinish)(fp); + break; + case ST_STOPPING: + NewState(fp, ST_STOPPED); + (fp->LayerFinish)(fp); + break; + case ST_REQSENT: /* XXX: 3p */ + case ST_ACKSENT: + case ST_ACKRCVD: + NewState(fp, ST_STOPPED); + (fp->LayerFinish)(fp); + break; + } + } +} + +void +FsmInitRestartCounter(fp) +struct fsm *fp; +{ + StopTimer(&fp->FsmTimer); + fp->FsmTimer.state = TIMER_STOPPED; + fp->FsmTimer.func = FsmTimeout; + fp->FsmTimer.arg = (void *)fp; + (fp->InitRestartCounter)(fp); +} + +/* + * Actions when receive packets + */ +void +FsmRecvConfigReq(fp, lhp, bp) /* RCR */ +struct fsm *fp; +struct fsmheader *lhp; +struct mbuf *bp; +{ + int plen; + int ackaction = 0; + + plen = plength(bp); + if (plen < sizeof(struct fsmconfig)) { +logprintf("** plen = %d\n", plen); + pfree(bp); + return; + } + + /* + * Check and process easy case + */ + switch (fp->state) { + case ST_INITIAL: + case ST_STARTING: + LogPrintf(LOG_LCP, "%s: Oops, RCR in %s.\n", + fp->name, StateNames[fp->state]); + pfree(bp); + return; + case ST_CLOSED: + (fp->SendTerminateAck)(fp); + pfree(bp); + return; + case ST_CLOSING: + case ST_STOPPING: +logprintf("## state = %d\n", fp->state); + pfree(bp); + return; + } + + (fp->DecodeConfig)(bp, MODE_REQ); + + if (nakp == NakBuff && rejp == RejBuff) + ackaction = 1; + + switch (fp->state) { + case ST_OPENED: + (fp->LayerDown)(fp); + FsmSendConfigReq(fp); + break; + case ST_STOPPED: + FsmInitRestartCounter(fp); + FsmSendConfigReq(fp); + break; + } + + if (rejp != RejBuff) + FsmSendConfigRej(fp, lhp, RejBuff, rejp - RejBuff); + if (nakp != NakBuff) + FsmSendConfigNak(fp, lhp, NakBuff, nakp - NakBuff); + if (ackaction) + FsmSendConfigAck(fp, lhp, AckBuff, ackp - AckBuff); + + switch (fp->state) { + case ST_STOPPED: + case ST_OPENED: + if (ackaction) + NewState(fp, ST_ACKSENT); + else + NewState(fp, ST_REQSENT); + break; + case ST_REQSENT: + if (ackaction) + NewState(fp, ST_ACKSENT); + break; + case ST_ACKRCVD: + if (ackaction) { + NewState(fp, ST_OPENED); + (fp->LayerUp)(fp); + } + break; + case ST_ACKSENT: + if (!ackaction) + NewState(fp, ST_REQSENT); + break; + } + pfree(bp); +} + +void +FsmRecvConfigAck(fp, lhp, bp) /* RCA */ +struct fsm *fp; +struct fsmheader *lhp; +struct mbuf *bp; +{ + switch (fp->state) { + case ST_CLOSED: + case ST_STOPPED: + (fp->SendTerminateAck)(fp); + break; + case ST_CLOSING: + case ST_STOPPING: + break; + case ST_REQSENT: + FsmInitRestartCounter(fp); + NewState(fp, ST_ACKRCVD); + break; + case ST_ACKRCVD: + FsmSendConfigReq(fp); + NewState(fp, ST_REQSENT); + break; + case ST_ACKSENT: + FsmInitRestartCounter(fp); + NewState(fp, ST_OPENED); + (fp->LayerUp)(fp); + break; + case ST_OPENED: + (fp->LayerDown)(fp); + FsmSendConfigReq(fp); + NewState(fp, ST_REQSENT); + break; + } + pfree(bp); +} + +void +FsmRecvConfigNak(fp, lhp, bp) /* RCN */ +struct fsm *fp; +struct fsmheader *lhp; +struct mbuf *bp; +{ + int plen; + + plen = plength(bp); + if (plen < sizeof(struct fsmconfig)) { + pfree(bp); + return; + } + + /* + * Check and process easy case + */ + switch (fp->state) { + case ST_INITIAL: + case ST_STARTING: + LogPrintf(LOG_LCP, "%s: Oops, RCN in %s.\n", + fp->name, StateNames[fp->state]); + pfree(bp); + return; + case ST_CLOSED: + case ST_STOPPED: + (fp->SendTerminateAck)(fp); + pfree(bp); + return; + case ST_CLOSING: + case ST_STOPPING: + pfree(bp); + return; + } + + (fp->DecodeConfig)(bp, MODE_NAK); + + switch (fp->state) { + case ST_REQSENT: + case ST_ACKSENT: + FsmInitRestartCounter(fp); + FsmSendConfigReq(fp); + break; + case ST_OPENED: + (fp->LayerDown)(fp); + /* Fall down */ + case ST_ACKRCVD: + FsmSendConfigReq(fp); + NewState(fp, ST_REQSENT); + break; + } + + pfree(bp); +} + +void +FsmRecvTermReq(fp, lhp, bp) /* RTR */ +struct fsm *fp; +struct fsmheader *lhp; +struct mbuf *bp; +{ + switch (fp->state) { + case ST_INITIAL: + case ST_STARTING: + LogPrintf(LOG_LCP, "%s: Oops, RTR in %s\n", fp->name, + StateNames[fp->state]); + break; + case ST_CLOSED: + case ST_STOPPED: + case ST_CLOSING: + case ST_STOPPING: + case ST_REQSENT: + (fp->SendTerminateAck)(fp); + break; + case ST_ACKRCVD: + case ST_ACKSENT: + (fp->SendTerminateAck)(fp); + NewState(fp, ST_REQSENT); + break; + case ST_OPENED: + (fp->LayerDown)(fp); + /* Zero Restart counter */ + (fp->SendTerminateAck)(fp); + NewState(fp, ST_STOPPING); + break; + } + pfree(bp); +} + +void +FsmRecvTermAck(fp, lhp, bp) /* RTA */ +struct fsm *fp; +struct fsmheader *lhp; +struct mbuf *bp; +{ + switch (fp->state) { + case ST_CLOSING: + NewState(fp, ST_CLOSED); + (fp->LayerFinish)(fp); + break; + case ST_STOPPING: + NewState(fp, ST_STOPPED); + (fp->LayerFinish)(fp); + break; + case ST_ACKRCVD: + NewState(fp, ST_REQSENT); + break; + case ST_OPENED: + (fp->LayerDown)(fp); + FsmSendConfigReq(fp); + NewState(fp, ST_REQSENT); + break; + } + pfree(bp); +} + +void +FsmRecvConfigRej(fp, lhp, bp) /* RCJ */ +struct fsm *fp; +struct fsmheader *lhp; +struct mbuf *bp; +{ + int plen; + + plen = plength(bp); + if (plen < sizeof(struct fsmconfig)) { + pfree(bp); + return; + } + LogPrintf(LOG_LCP, "%s: RecvConfigRej.\n", fp->name); + + /* + * Check and process easy case + */ + switch (fp->state) { + case ST_INITIAL: + case ST_STARTING: + LogPrintf(LOG_LCP, "%s: Oops, RCJ in %s.\n", + fp->name, StateNames[fp->state]); + pfree(bp); + return; + case ST_CLOSED: + case ST_STOPPED: + (fp->SendTerminateAck)(fp); + pfree(bp); + return; + case ST_CLOSING: + case ST_STOPPING: + pfree(bp); + return; + } + + (fp->DecodeConfig)(bp, MODE_REJ); + + switch (fp->state) { + case ST_REQSENT: + case ST_ACKSENT: + FsmInitRestartCounter(fp); + FsmSendConfigReq(fp); + break; + case ST_OPENED: + (fp->LayerDown)(fp); + /* Fall down */ + case ST_ACKRCVD: + FsmSendConfigReq(fp); + NewState(fp, ST_REQSENT); + break; + } + pfree(bp); +} + +void +FsmRecvCodeRej(fp, lhp, bp) +struct fsm *fp; +struct fsmheader *lhp; +struct mbuf *bp; +{ + LogPrintf(LOG_LCP, "%s: RecvCodeRej\n", fp->name); + pfree(bp); +} + +void +FsmRecvProtoRej(fp, lhp, bp) +struct fsm *fp; +struct fsmheader *lhp; +struct mbuf *bp; +{ + u_short *sp, proto; + + sp = (u_short *)MBUF_CTOP(bp); + proto = ntohs(*sp); + LogPrintf(LOG_LCP, "-- Protocol (%04x) was rejected.\n", proto); + + switch (proto) { + case PROTO_LQR: + StopLqr(LQM_LQR); + break; + case PROTO_CCP: + fp = &CcpFsm; + (fp->LayerFinish)(fp); + switch (fp->state) { + case ST_CLOSED: + case ST_CLOSING: + NewState(fp, ST_CLOSED); + default: + NewState(fp, ST_STOPPED); + break; + } + break; + } + pfree(bp); +} + +void +FsmRecvEchoReq(fp, lhp, bp) +struct fsm *fp; +struct fsmheader *lhp; +struct mbuf *bp; +{ + u_char *cp; + u_long *lp, magic; + + cp = MBUF_CTOP(bp); + lp = (u_long *)cp; + magic = ntohl(*lp); + if (magic != LcpInfo.his_magic) { + logprintf("RecvEchoReq: his magic is bad!!\n"); + /* XXX: We should send terminate request */ + } + + if (fp->state == ST_OPENED) { + *lp = htonl(LcpInfo.want_magic); /* Insert local magic number */ + LogPrintf(LOG_LCP, "%s: SendEchoRep(%s)\n", fp->name, StateNames[fp->state]); + FsmOutput(fp, CODE_ECHOREP, lhp->id, cp, plength(bp)); + } + pfree(bp); +} + +void +FsmRecvEchoRep(fp, lhp, bp) +struct fsm *fp; +struct fsmheader *lhp; +struct mbuf *bp; +{ + u_long *lp, magic; + + lp = (u_long *)MBUF_CTOP(bp); + magic = ntohl(*lp); + if (magic != 0 && magic != LcpInfo.his_magic) { + logprintf("RecvEchoRep: his magic is wrong! expect: %x got: %x\n", + LcpInfo.his_magic, magic); + /* + * XXX: We should send terminate request. But poor implementation + * may die as a result. + */ + } + RecvEchoLqr(bp); + pfree(bp); +} + +void +FsmRecvDiscReq(fp, lhp, bp) +struct fsm *fp; +struct fsmheader *lhp; +struct mbuf *bp; +{ + LogPrintf(LOG_LCP, "%s: RecvDiscReq\n", fp->name); + pfree(bp); +} + +void +FsmRecvIdent(fp, lhp, bp) +struct fsm *fp; +struct fsmheader *lhp; +struct mbuf *bp; +{ + LogPrintf(LOG_LCP, "%s: RecvIdent\n", fp->name); + pfree(bp); +} + +void +FsmRecvTimeRemain(fp, lhp, bp) +struct fsm *fp; +struct fsmheader *lhp; +struct mbuf *bp; +{ + LogPrintf(LOG_LCP, "%s: RecvTimeRemain\n", fp->name); + pfree(bp); +} + +void +FsmRecvResetReq(fp, lhp, bp) +struct fsm *fp; +struct fsmheader *lhp; +struct mbuf *bp; +{ + LogPrintf(LOG_LCP, "%s: RecvResetReq\n", fp->name); + CcpRecvResetReq(fp); + LogPrintf(LOG_LCP, "%s: SendResetAck\n", fp->name); + FsmOutput(fp, CODE_RESETACK, fp->reqid, NULL, 0); + pfree(bp); +} + +void +FsmRecvResetAck(fp, lhp, bp) +struct fsm *fp; +struct fsmheader *lhp; +struct mbuf *bp; +{ + LogPrintf(LOG_LCP, "%s: RecvResetAck\n", fp->name); + fp->reqid++; + pfree(bp); +} + +struct fsmcodedesc FsmCodes[] = { + { FsmRecvConfigReq, "Configure Request", }, + { FsmRecvConfigAck, "Configure Ack", }, + { FsmRecvConfigNak, "Configure Nak", }, + { FsmRecvConfigRej, "Configure Reject", }, + { FsmRecvTermReq, "Terminate Request", }, + { FsmRecvTermAck, "Terminate Ack", }, + { FsmRecvCodeRej, "Code Reject", }, + { FsmRecvProtoRej, "Protocol Reject", }, + { FsmRecvEchoReq, "Echo Request", }, + { FsmRecvEchoRep, "Echo Reply", }, + { FsmRecvDiscReq, "Discard Request", }, + { FsmRecvIdent, "Ident", }, + { FsmRecvTimeRemain, "Time Remain", }, + { FsmRecvResetReq, "Reset Request", }, + { FsmRecvResetAck, "Reset Ack", }, +}; + +void +FsmInput(fp, bp) +struct fsm *fp; +struct mbuf *bp; +{ + int len; + struct fsmheader *lhp; + struct fsmcodedesc *codep; + + len = plength(bp); + if (len < sizeof(struct fsmheader)) { + pfree(bp); + return; + } + lhp = (struct fsmheader *)MBUF_CTOP(bp); + if (lhp->code == 0 || lhp->code > fp->max_code) { + pfree(bp); /* XXX: Should send code reject */ + return; + } + + bp->offset += sizeof(struct fsmheader); + bp->cnt -= sizeof(struct fsmheader); + + codep = FsmCodes + lhp->code - 1; + LogPrintf(LOG_LCP, "%s: Received %s (%d) state = %s (%d)\n", + fp->name, codep->name, lhp->code, StateNames[fp->state], fp->state); +#ifdef DEBUG + LogMemory(); +#endif + (codep->action)(fp, lhp, bp); +#ifdef DEBUG + LogMemory(); +#endif +} -- cgit v1.1