📄 fsm.c
字号:
/* * fsm.c - {Link, IP} Control Protocol Finite State Machine. * * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The name "Carnegie Mellon University" must not be used to * endorse or promote products derived from this software without * prior written permission. For permission or any legal * details, please contact * Office of Technology Transfer * Carnegie Mellon University * 5000 Forbes Avenue * Pittsburgh, PA 15213-3890 * (412) 268-4387, fax: (412) 268-7395 * tech-transfer@andrew.cmu.edu * * 4. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by Computing Services * at Carnegie Mellon University (http://www.cmu.edu/computing/)." * * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */#define RCSID "$Id: fsm.c,v 1.23 2004/11/13 02:28:15 paulus Exp $"/* * TODO: * Randomize fsm id on link/init. * Deal with variable outgoing MTU. */#include <stdio.h>#include <string.h>#include <sys/types.h>#include "pppd.h"#include "fsm.h"static const char rcsid[] = RCSID;static void fsm_timeout __P((void *));static void fsm_rconfreq __P((fsm *, int, u_char *, int));static void fsm_rconfack __P((fsm *, int, u_char *, int));static void fsm_rconfnakrej __P((fsm *, int, int, u_char *, int));static void fsm_rtermreq __P((fsm *, int, u_char *, int));static void fsm_rtermack __P((fsm *));static void fsm_rcoderej __P((fsm *, u_char *, int));static void fsm_sconfreq __P((fsm *, int));#define PROTO_NAME(f) ((f)->callbacks->proto_name)int peer_mru[NUM_PPP];/* * fsm_init - Initialize fsm. * * Initialize fsm state. */voidfsm_init(f) fsm *f;{ f->state = INITIAL; f->flags = 0; f->id = 0; /* XXX Start with random id? */ f->timeouttime = DEFTIMEOUT; f->maxconfreqtransmits = DEFMAXCONFREQS; f->maxtermtransmits = DEFMAXTERMREQS; f->maxnakloops = DEFMAXNAKLOOPS; f->term_reason_len = 0;}/* * fsm_lowerup - The lower layer is up. */voidfsm_lowerup(f) fsm *f;{ switch( f->state ){ case INITIAL: f->state = CLOSED; break; case STARTING: if( f->flags & OPT_SILENT ) f->state = STOPPED; else { /* Send an initial configure-request */ fsm_sconfreq(f, 0); f->state = REQSENT; } break; default: FSMDEBUG(("%s: Up event in state %d!", PROTO_NAME(f), f->state)); }}/* * fsm_lowerdown - The lower layer is down. * * Cancel all timeouts and inform upper layers. */voidfsm_lowerdown(f) fsm *f;{ switch( f->state ){ case CLOSED: f->state = INITIAL; break; case STOPPED: f->state = STARTING; if( f->callbacks->starting ) (*f->callbacks->starting)(f); break; case CLOSING: f->state = INITIAL; UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ break; case STOPPING: case REQSENT: case ACKRCVD: case ACKSENT: f->state = STARTING; UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ break; case OPENED: if( f->callbacks->down ) (*f->callbacks->down)(f); f->state = STARTING; break; default: FSMDEBUG(("%s: Down event in state %d!", PROTO_NAME(f), f->state)); }}/* * fsm_open - Link is allowed to come up. */voidfsm_open(f) fsm *f;{ switch( f->state ){ case INITIAL: f->state = STARTING; if( f->callbacks->starting ) (*f->callbacks->starting)(f); break; case CLOSED: if( f->flags & OPT_SILENT ) f->state = STOPPED; else { /* Send an initial configure-request */ fsm_sconfreq(f, 0); f->state = REQSENT; } break; case CLOSING: f->state = STOPPING; /* fall through */ case STOPPED: case OPENED: if( f->flags & OPT_RESTART ){ fsm_lowerdown(f); fsm_lowerup(f); } break; }}/* * terminate_layer - Start process of shutting down the FSM * * Cancel any timeout running, notify upper layers we're done, and * send a terminate-request message as configured. */static voidterminate_layer(f, nextstate) fsm *f; int nextstate;{ if( f->state != 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 and send Terminate-Request */ f->retransmits = f->maxtermtransmits; fsm_sdata(f, TERMREQ, f->reqid = ++f->id, (u_char *) f->term_reason, f->term_reason_len); if (f->retransmits == 0) { /* * User asked for no terminate requests at all; just close it. * We've already fired off one Terminate-Request just to be nice * to the peer, but we're not going to wait for a reply. */ f->state = nextstate == CLOSING ? CLOSED : STOPPED; if( f->callbacks->finished ) (*f->callbacks->finished)(f); return; } TIMEOUT(fsm_timeout, f, f->timeouttime); --f->retransmits; f->state = nextstate;}/* * fsm_close - Start closing connection. * * Cancel timeouts and either initiate close or possibly go directly to * the CLOSED state. */voidfsm_close(f, reason) fsm *f; char *reason;{ f->term_reason = reason; f->term_reason_len = (reason == NULL? 0: strlen(reason)); switch( f->state ){ case STARTING: f->state = INITIAL; break; case STOPPED: f->state = CLOSED; break; case STOPPING: f->state = CLOSING; break; case REQSENT: case ACKRCVD: case ACKSENT: case OPENED: terminate_layer(f, CLOSING); break; }}/* * fsm_timeout - Timeout expired. */static voidfsm_timeout(arg) void *arg;{ fsm *f = (fsm *) arg; switch (f->state) { case CLOSING: case STOPPING: if( f->retransmits <= 0 ){ /* * We've waited for an ack long enough. Peer probably heard us. */ f->state = (f->state == CLOSING)? CLOSED: STOPPED; if( f->callbacks->finished ) (*f->callbacks->finished)(f); } else { /* Send Terminate-Request */ 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; } break; case REQSENT: case ACKRCVD: case ACKSENT: if (f->retransmits <= 0) { warn("%s: timeout sending Config-Requests\n", PROTO_NAME(f)); f->state = STOPPED; if( (f->flags & OPT_PASSIVE) == 0 && f->callbacks->finished ) (*f->callbacks->finished)(f); } else { /* Retransmit the configure-request */ if (f->callbacks->retransmit) (*f->callbacks->retransmit)(f); fsm_sconfreq(f, 1); /* Re-send Configure-Request */ if( f->state == ACKRCVD ) f->state = REQSENT; } break; default: FSMDEBUG(("%s: Timeout event in state %d!", PROTO_NAME(f), f->state)); }}/* * fsm_input - Input packet. */voidfsm_input(f, inpacket, l) fsm *f; u_char *inpacket; int l;{ u_char *inp; u_char code, id; int len; /* * Parse header (code, id and length). * If packet too short, drop it. */ inp = inpacket; if (l < HEADERLEN) { FSMDEBUG(("fsm_input(%x): Rcvd short header.", f->protocol)); return; } GETCHAR(code, inp); GETCHAR(id, inp); GETSHORT(len, inp); if (len < HEADERLEN) { FSMDEBUG(("fsm_input(%x): Rcvd illegal length.", f->protocol)); return; } if (len > l) { FSMDEBUG(("fsm_input(%x): Rcvd short packet.", f->protocol)); return; } len -= HEADERLEN; /* subtract header length */ if( f->state == INITIAL || f->state == STARTING ){ FSMDEBUG(("fsm_input(%x): Rcvd packet in state %d.", f->protocol, f->state)); return; } /* * 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; }}/*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -