📄 fsm.c
字号:
/****************************************************************************** fsm.c - Network Control Protocol Finite State Machine program file.** Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.* portions Copyright (c) 1997 by Global Election Systems Inc.** The authors hereby grant permission to use, copy, modify, distribute,* and license this software and its documentation for any purpose, provided* that existing copyright notices are retained in all copies and that this* notice and the following disclaimer are included verbatim in any * distributions. No written agreement, license, or royalty fee is required* for any of the authorized uses.** THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.******************************************************************************** REVISION HISTORY** 03-01-01 Marc Boucher <marc@mbsi.ca>* Ported to lwIP.* 97-12-01 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.* Original based on BSD fsm.c.*****************************************************************************//* * fsm.c - {Link, IP} Control Protocol Finite State Machine. * * Copyright (c) 1989 Carnegie Mellon University. * All rights reserved. * * 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 Carnegie Mellon University. The name of the * University 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. *//* * TODO: * Randomize fsm id on link/init. * Deal with variable outgoing MTU. */#include "lwip/opt.h"#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */#include "ppp.h"#include "pppdebug.h"#include "fsm.h"/*************************//*** LOCAL DEFINITIONS ***//*************************/#if PPP_DEBUGstatic const char *ppperr_strerr[] = { "LS_INITIAL", /* LS_INITIAL 0 */ "LS_STARTING", /* LS_STARTING 1 */ "LS_CLOSED", /* LS_CLOSED 2 */ "LS_STOPPED", /* LS_STOPPED 3 */ "LS_CLOSING", /* LS_CLOSING 4 */ "LS_STOPPING", /* LS_STOPPING 5 */ "LS_REQSENT", /* LS_REQSENT 6 */ "LS_ACKRCVD", /* LS_ACKRCVD 7 */ "LS_ACKSENT", /* LS_ACKSENT 8 */ "LS_OPENED" /* LS_OPENED 9 */};#endif /* PPP_DEBUG *//************************//*** LOCAL DATA TYPES ***//************************//***********************************//*** LOCAL FUNCTION DECLARATIONS ***//***********************************/static void fsm_timeout (void *);static void fsm_rconfreq (fsm *, u_char, u_char *, int);static void fsm_rconfack (fsm *, int, u_char *, int);static void fsm_rconfnakrej (fsm *, int, int, u_char *, int);static void fsm_rtermreq (fsm *, int, u_char *, int);static void fsm_rtermack (fsm *);static void fsm_rcoderej (fsm *, u_char *, int);static void fsm_sconfreq (fsm *, int);#define PROTO_NAME(f) ((f)->callbacks->proto_name)/******************************//*** PUBLIC DATA STRUCTURES ***//******************************//*****************************//*** LOCAL DATA STRUCTURES ***//*****************************/int peer_mru[NUM_PPP];/***********************************//*** PUBLIC FUNCTION DEFINITIONS ***//***********************************//* * fsm_init - Initialize fsm. * * Initialize fsm state. */voidfsm_init(fsm *f){ f->state = LS_INITIAL; f->flags = 0; f->id = 0; /* XXX Start with random id? */ f->timeouttime = FSM_DEFTIMEOUT; f->maxconfreqtransmits = FSM_DEFMAXCONFREQS; f->maxtermtransmits = FSM_DEFMAXTERMREQS; f->maxnakloops = FSM_DEFMAXNAKLOOPS; f->term_reason_len = 0;}/* * fsm_lowerup - The lower layer is up. */voidfsm_lowerup(fsm *f){ int oldState = f->state; LWIP_UNUSED_ARG(oldState); switch( f->state ) { case LS_INITIAL: f->state = LS_CLOSED; break; case LS_STARTING: if( f->flags & OPT_SILENT ) { f->state = LS_STOPPED; } else { /* Send an initial configure-request */ fsm_sconfreq(f, 0); f->state = LS_REQSENT; } break; default: FSMDEBUG((LOG_INFO, "%s: Up event in state %d (%s)!\n", PROTO_NAME(f), f->state, ppperr_strerr[f->state])); } FSMDEBUG((LOG_INFO, "%s: lowerup state %d (%s) -> %d (%s)\n", PROTO_NAME(f), oldState, ppperr_strerr[oldState], f->state, ppperr_strerr[f->state]));}/* * fsm_lowerdown - The lower layer is down. * * Cancel all timeouts and inform upper layers. */voidfsm_lowerdown(fsm *f){ int oldState = f->state; LWIP_UNUSED_ARG(oldState); switch( f->state ) { case LS_CLOSED: f->state = LS_INITIAL; break; case LS_STOPPED: f->state = LS_STARTING; if( f->callbacks->starting ) { (*f->callbacks->starting)(f); } break; case LS_CLOSING: f->state = LS_INITIAL; UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ break; case LS_STOPPING: case LS_REQSENT: case LS_ACKRCVD: case LS_ACKSENT: f->state = LS_STARTING; UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ break; case LS_OPENED: if( f->callbacks->down ) { (*f->callbacks->down)(f); } f->state = LS_STARTING; break; default: FSMDEBUG((LOG_INFO, "%s: Down event in state %d (%s)!\n", PROTO_NAME(f), f->state, ppperr_strerr[f->state])); } FSMDEBUG((LOG_INFO, "%s: lowerdown state %d (%s) -> %d (%s)\n", PROTO_NAME(f), oldState, ppperr_strerr[oldState], f->state, ppperr_strerr[f->state]));}/* * fsm_open - Link is allowed to come up. */voidfsm_open(fsm *f){ int oldState = f->state; LWIP_UNUSED_ARG(oldState); switch( f->state ) { case LS_INITIAL: f->state = LS_STARTING; if( f->callbacks->starting ) { (*f->callbacks->starting)(f); } break; case LS_CLOSED: if( f->flags & OPT_SILENT ) { f->state = LS_STOPPED; } else { /* Send an initial configure-request */ fsm_sconfreq(f, 0); f->state = LS_REQSENT; } break; case LS_CLOSING: f->state = LS_STOPPING; /* fall through */ case LS_STOPPED: case LS_OPENED: if( f->flags & OPT_RESTART ) { fsm_lowerdown(f); fsm_lowerup(f); } break; } FSMDEBUG((LOG_INFO, "%s: open state %d (%s) -> %d (%s)\n", PROTO_NAME(f), oldState, ppperr_strerr[oldState], f->state, ppperr_strerr[f->state]));}/* * fsm_close - Start closing connection. * * Cancel timeouts and either initiate close or possibly go directly to * the LS_CLOSED state. */voidfsm_close(fsm *f, char *reason){ int oldState = f->state; LWIP_UNUSED_ARG(oldState); f->term_reason = reason; f->term_reason_len = (reason == NULL? 0: strlen(reason)); switch( f->state ) { case LS_STARTING: f->state = LS_INITIAL; break; case LS_STOPPED: f->state = LS_CLOSED; break; case LS_STOPPING: f->state = LS_CLOSING; break; case LS_REQSENT: case LS_ACKRCVD: case LS_ACKSENT: case LS_OPENED: if( f->state != LS_OPENED ) { UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ } else if( f->callbacks->down ) { (*f->callbacks->down)(f); /* Inform upper layers we're down */ } /* Init restart counter, send Terminate-Request */ f->retransmits = f->maxtermtransmits; fsm_sdata(f, TERMREQ, f->reqid = ++f->id, (u_char *) f->term_reason, f->term_reason_len); TIMEOUT(fsm_timeout, f, f->timeouttime); --f->retransmits; f->state = LS_CLOSING; break; } FSMDEBUG((LOG_INFO, "%s: close reason=%s state %d (%s) -> %d (%s)\n", PROTO_NAME(f), reason, oldState, ppperr_strerr[oldState], f->state, ppperr_strerr[f->state]));}/* * fsm_sdata - Send some data. * * Used for all packets sent to our peer by this module. */voidfsm_sdata( fsm *f, u_char code, u_char id, u_char *data, int datalen){ u_char *outp; int outlen; /* Adjust length to be smaller than MTU */ outp = outpacket_buf[f->unit]; if (datalen > peer_mru[f->unit] - (int)HEADERLEN) { datalen = peer_mru[f->unit] - HEADERLEN; } if (datalen && data != outp + PPP_HDRLEN + HEADERLEN) { BCOPY(data, outp + PPP_HDRLEN + HEADERLEN, datalen); } outlen = datalen + HEADERLEN; MAKEHEADER(outp, f->protocol); PUTCHAR(code, outp); PUTCHAR(id, outp); PUTSHORT(outlen, outp); pppWrite(f->unit, outpacket_buf[f->unit], outlen + PPP_HDRLEN); FSMDEBUG((LOG_INFO, "fsm_sdata(%s): Sent code %d,%d,%d.\n", PROTO_NAME(f), code, id, outlen));}/* * fsm_input - Input packet. */voidfsm_input(fsm *f, u_char *inpacket, int l){ u_char *inp = inpacket; u_char code, id; int len; /* * Parse header (code, id and length). * If packet too short, drop it. */ if (l < HEADERLEN) { FSMDEBUG((LOG_WARNING, "fsm_input(%x): Rcvd short header.\n", f->protocol)); return; } GETCHAR(code, inp); GETCHAR(id, inp); GETSHORT(len, inp); if (len < HEADERLEN) { FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd illegal length.\n", f->protocol)); return; } if (len > l) { FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd short packet.\n", f->protocol)); return; } len -= HEADERLEN; /* subtract header length */ if( f->state == LS_INITIAL || f->state == LS_STARTING ) { FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd packet in state %d (%s).\n", f->protocol, f->state, ppperr_strerr[f->state])); return; } FSMDEBUG((LOG_INFO, "fsm_input(%s):%d,%d,%d\n", PROTO_NAME(f), code, id, l)); /* * Action depends on code. */ switch (code) { case CONFREQ: fsm_rconfreq(f, id, inp, len); break; case CONFACK: fsm_rconfack(f, id, inp, len); break; case CONFNAK: case CONFREJ: fsm_rconfnakrej(f, code, id, inp, len); break; case TERMREQ: fsm_rtermreq(f, id, inp, len); break; case TERMACK: fsm_rtermack(f); break; case CODEREJ: fsm_rcoderej(f, inp, len); break; default: if( !f->callbacks->extcode || !(*f->callbacks->extcode)(f, code, id, inp, len) ) { fsm_sdata(f, CODEREJ, ++f->id, inpacket, len + HEADERLEN); } break; }}/* * fsm_protreject - Peer doesn't speak this protocol. * * Treat this as a catastrophic error (RXJ-). */voidfsm_protreject(fsm *f){ switch( f->state ) { case LS_CLOSING: UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ /* fall through */ case LS_CLOSED: f->state = LS_CLOSED; if( f->callbacks->finished ) { (*f->callbacks->finished)(f); } break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -