diff options
Diffstat (limited to 'libexec/pppd/fsm.c')
-rw-r--r-- | libexec/pppd/fsm.c | 1006 |
1 files changed, 505 insertions, 501 deletions
diff --git a/libexec/pppd/fsm.c b/libexec/pppd/fsm.c index 19bfb97595c3..ba8b76082d69 100644 --- a/libexec/pppd/fsm.c +++ b/libexec/pppd/fsm.c @@ -17,10 +17,12 @@ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ +#ifndef lint +static char rcsid[] = "$Id: fsm.c,v 1.3 1994/03/30 09:38:12 jkh Exp $"; +#endif + /* * TODO: - * Mechanism to exit() and/or drop DTR. - * Hold-down on open? * Randomize fsm id on link/init. * Deal with variable outgoing MTU. */ @@ -30,27 +32,24 @@ /*#include <malloc.h>*/ #include <syslog.h> -#ifdef STREAMS -#include <sys/stream.h> -#include <sys/socket.h> -#include <net/if.h> -#endif - -#include <net/ppp.h> +#include "ppp.h" #include "pppd.h" #include "fsm.h" extern char *proto_name(); static void fsm_timeout __ARGS((caddr_t)); -static void fsm_rconfack __ARGS((fsm *, u_char *, int, int)); -static void fsm_rconfnak __ARGS((fsm *, u_char *, int, int)); -static void fsm_rconfrej __ARGS((fsm *, u_char *, int, int)); +static void fsm_rconfreq __ARGS((fsm *, int, u_char *, int)); +static void fsm_rconfack __ARGS((fsm *, int, u_char *, int)); +static void fsm_rconfnakrej __ARGS((fsm *, int, int, u_char *, int)); static void fsm_rtermreq __ARGS((fsm *, int)); static void fsm_rtermack __ARGS((fsm *)); static void fsm_rcoderej __ARGS((fsm *, u_char *, int)); -static void fsm_rprotrej __ARGS((fsm *, u_char *, int)); -static void fsm_sconfreq __ARGS((fsm *)); +static void fsm_sconfreq __ARGS((fsm *, int)); + +#define PROTO_NAME(f) ((f)->callbacks->proto_name) + +int peer_mru[_NPPP]; /* @@ -59,226 +58,225 @@ static void fsm_sconfreq __ARGS((fsm *)); * Initialize fsm state. */ void - fsm_init(f) -fsm *f; +fsm_init(f) + fsm *f; { - f->state = CLOSED; + 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; } /* - * fsm_activeopen - Actively open connection. - * - * Set new state, reset desired options and send requests. + * fsm_lowerup - The lower layer is up. */ void - fsm_activeopen(f) -fsm *f; +fsm_lowerup(f) + fsm *f; { - f->flags &= ~(AOPENDING|POPENDING); /* Clear pending flags */ - if (f->state == REQSENT || /* Already actively open(ing)? */ - f->state == ACKRCVD || - f->state == ACKSENT || - f->state == OPEN) - return; - if (f->state == TERMSENT || /* Closing or */ - !(f->flags & LOWERUP)) { /* lower layer down? */ - f->flags |= AOPENDING; /* Wait for desired event */ - return; - } - if (f->callbacks->resetci) - (*f->callbacks->resetci)(f); /* Reset options */ - fsm_sconfreq(f); /* Send Configure-Request */ - TIMEOUT(fsm_timeout, (caddr_t) f, f->timeouttime); - f->state = REQSENT; - f->retransmits = 0; /* Reset retransmits count */ - f->nakloops = 0; /* Reset nakloops count */ -} + 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; -/* - * fsm_passiveopen - Passively open connection. - * - * Set new state and reset desired options. - */ -void - fsm_passiveopen(f) -fsm *f; -{ - f->flags &= ~(AOPENDING|POPENDING); /* Clear pending flags */ - if (f->state == LISTEN || /* Already passively open(ing)? */ - f->state == OPEN) - return; - if (f->state == REQSENT || /* Active-Opening or */ - f->state == ACKRCVD || - f->state == ACKSENT || - f->state == TERMSENT || /* closing or */ - !(f->flags & LOWERUP)) { /* lower layer down? */ - f->flags |= POPENDING; /* Wait for desired event */ - return; + default: + FSMDEBUG((LOG_INFO, "%s: Up event in state %d!", + PROTO_NAME(f), f->state)); } - if (f->callbacks->resetci) - (*f->callbacks->resetci)(f); /* Reset options */ - f->state = LISTEN; - f->retransmits = 0; /* Reset retransmits count */ - f->nakloops = 0; /* Reset nakloops count */ } /* - * fsm_close - Start closing connection. + * fsm_lowerdown - The lower layer is down. * - * Cancel timeouts and either initiate close or possibly go directly to - * the CLOSED state. + * Cancel all timeouts and inform upper layers. */ void - fsm_close(f) -fsm *f; +fsm_lowerdown(f) + fsm *f; { - f->flags &= ~(AOPENDING|POPENDING); /* Clear pending flags */ - if (f->state == CLOSED || /* Already CLOSED or Closing? */ - f->state == TERMSENT) - return; - if (f->state == REQSENT || /* Timeout pending for Open? */ - f->state == ACKRCVD || - f->state == ACKSENT) + 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, (caddr_t) f); /* Cancel timeout */ - if (f->state == OPEN && /* Open? */ - f->callbacks->down) - (*f->callbacks->down)(f); /* Inform upper layers we're down */ - if (f->state == ACKSENT || /* Could peer be OPEN? */ - f->state == OPEN) { - fsm_sdata(f, TERMREQ, f->reqid = ++f->id, NULL, 0); - /* Send Terminate-Request */ - TIMEOUT(fsm_timeout, (caddr_t) f, f->timeouttime); - f->state = TERMSENT; - f->retransmits = 0; /* Reset retransmits count */ - } - else { - f->state = CLOSED; - if (f->callbacks->closed) - (*f->callbacks->closed)(f); /* Exit/restart/etc. */ + break; + + case STOPPING: + case REQSENT: + case ACKRCVD: + case ACKSENT: + f->state = STARTING; + UNTIMEOUT(fsm_timeout, (caddr_t) f); /* Cancel timeout */ + break; + + case OPENED: + if( f->callbacks->down ) + (*f->callbacks->down)(f); + f->state = STARTING; + break; + + default: + FSMDEBUG((LOG_INFO, "%s: Down event in state %d!", + PROTO_NAME(f), f->state)); } } /* - * fsm_timeout - Timeout expired. + * fsm_open - Link is allowed to come up. */ -static void - fsm_timeout(arg) -caddr_t arg; +void +fsm_open(f) + fsm *f; { - fsm *f = (fsm *) arg; - switch (f->state) { - case REQSENT: - case ACKRCVD: - case ACKSENT: - if (f->flags & POPENDING) { /* Go passive? */ - f->state = CLOSED; /* Pretend for a moment... */ - fsm_passiveopen(f); - return; - } - if (f->retransmits > f->maxconfreqtransmits) { - if (f->nakloops > f->maxnakloops) { - syslog(LOG_INFO, "%s: timeout sending Config-Requests", - proto_name(f->protocol)); - } else - syslog(LOG_INFO, "%s: timed out. Config-Requests not accepted", - proto_name(f->protocol)); - - /* timeout sending config-requests */ - fsm_close(f); - - return; - } - if (f->callbacks->retransmit) /* If there is a retransmit rtn? */ - (*f->callbacks->retransmit)(f); - fsm_sconfreq(f); /* Send Configure-Request */ - TIMEOUT(fsm_timeout, (caddr_t) f, f->timeouttime); - f->state = REQSENT; - ++f->retransmits; - f->nakloops = 0; + switch( f->state ){ + case INITIAL: + f->state = STARTING; + if( f->callbacks->starting ) + (*f->callbacks->starting)(f); break; - case TERMSENT: - if (f->flags & POPENDING) { /* Go passive? */ - f->state = CLOSED; /* Pretend for a moment... */ - fsm_passiveopen(f); - return; + case CLOSED: + if( f->flags & OPT_SILENT ) + f->state = STOPPED; + else { + /* Send an initial configure-request */ + fsm_sconfreq(f, 0); + f->state = REQSENT; } - if (++f->retransmits > f->maxtermtransmits) { - /* - * We've waited for an ack long enough. Peer probably heard us. - */ - f->state = CLOSED; - if (f->callbacks->closed) - (*f->callbacks->closed)(f); /* Exit/restart/etc. */ - return; + break; + + case CLOSING: + f->state = STOPPING; + /* fall through */ + case STOPPED: + case OPENED: + if( f->flags & OPT_RESTART ){ + fsm_lowerdown(f); + fsm_lowerup(f); } - if (f->callbacks->retransmit) /* If there is a retransmit rtn? */ - (*f->callbacks->retransmit)(f); - fsm_sdata(f, TERMREQ, f->reqid = ++f->id, NULL, 0); - /* Send Terminate-Request */ - TIMEOUT(fsm_timeout, (caddr_t) f, f->timeouttime); - ++f->retransmits; + break; } } /* - * fsm_lowerup - The lower layer is up. + * fsm_close - Start closing connection. * - * Start Active or Passive Open if pending. + * Cancel timeouts and either initiate close or possibly go directly to + * the CLOSED state. */ void - fsm_lowerup(f) -fsm *f; +fsm_close(f) + fsm *f; { - f->flags |= LOWERUP; - if (f->flags & AOPENDING) /* Attempting Active-Open? */ - fsm_activeopen(f); /* Try it now */ - else if (f->flags & POPENDING) /* Attempting Passive-Open? */ - fsm_passiveopen(f); /* Try it now */ -} + 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: + if( f->state != OPENED ) + UNTIMEOUT(fsm_timeout, (caddr_t) f); /* Cancel timeout */ + else if( f->callbacks->down ) + (*f->callbacks->down)(f); /* Inform upper layers we're down */ -/* - * fsm_lowerdown - The lower layer is down. - * - * Cancel all timeouts and inform upper layers. - */ -void - fsm_lowerdown(f) -fsm *f; -{ - f->flags &= ~LOWERUP; - if (f->state == REQSENT || /* Timeout pending? */ - f->state == ACKRCVD || - f->state == ACKSENT || - f->state == TERMSENT) - UNTIMEOUT(fsm_timeout, (caddr_t) f); /* Cancel timeout */ - if (f->state == OPEN && /* OPEN? */ - f->callbacks->down) - (*f->callbacks->down)(f); /* Inform upper layers */ - f->state = CLOSED; - if (f->callbacks->closed) - (*f->callbacks->closed)(f); /* Exit/restart/etc. */ + /* Init restart counter, send Terminate-Request */ + f->retransmits = f->maxtermtransmits; + fsm_sdata(f, TERMREQ, f->reqid = ++f->id, NULL, 0); + TIMEOUT(fsm_timeout, (caddr_t) f, f->timeouttime); + --f->retransmits; + + f->state = CLOSING; + break; + } } /* - * fsm_protreject - Peer doesn't speak this protocol. - * - * Pretend that the lower layer went down. + * fsm_timeout - Timeout expired. */ -void - fsm_protreject(f) -fsm *f; +static void +fsm_timeout(arg) + caddr_t arg; { - fsm_lowerdown(f); + 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, NULL, 0); + TIMEOUT(fsm_timeout, (caddr_t) f, f->timeouttime); + --f->retransmits; + } + break; + + case REQSENT: + case ACKRCVD: + case ACKSENT: + if (f->retransmits <= 0) { + syslog(LOG_WARNING, "%s: timeout sending Config-Requests", + 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((LOG_INFO, "%s: Timeout event in state %d!", + PROTO_NAME(f), f->state)); + } } @@ -286,302 +284,262 @@ fsm *f; * fsm_input - Input packet. */ void - fsm_input(f, inpacket, l) -fsm *f; -u_char *inpacket; -int l; +fsm_input(f, inpacket, l) + fsm *f; + u_char *inpacket; + int l; { - u_char *inp, *outp; - u_char code, id; - int len; - - /* - * Parse header (code, id and length). - * If packet too short, drop it. - */ - inp = inpacket; - if (l < HEADERLEN) { - FSMDEBUG((LOG_WARNING, "fsm_input(%x): Rcvd short header.", f->protocol)) - return; - } - GETCHAR(code, inp); - GETCHAR(id, inp); - GETSHORT(len, inp); - if (len < HEADERLEN) { - FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd illegal length.", - f->protocol)) - return; - } - if (len > l) { - FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd short packet.", - f->protocol)) - return; - } - len -= HEADERLEN; /* subtract header length */ - - /* - * Action depends on code. - */ - switch (code) { - case CONFREQ: - FSMDEBUG((LOG_INFO, "fsm_rconfreq(%x): Rcvd id %d.", - f->protocol, id)) - - if (f->state == TERMSENT) - return; - if (f->state == CLOSED) { - fsm_sdata(f, TERMACK, id, NULL, 0); - return; + u_char *inp, *outp; + u_char code, id; + int len; + + /* + * Parse header (code, id and length). + * If packet too short, drop it. + */ + inp = inpacket; + if (l < HEADERLEN) { + FSMDEBUG((LOG_WARNING, "fsm_input(%x): Rcvd short header.", + f->protocol)); + return; } - if (f->state == OPEN && f->callbacks->down) - (*f->callbacks->down)(f); /* Inform upper layers */ - if (f->state == OPEN || f->state == LISTEN) { - /* XXX Possibly need hold-down on OPEN? */ - fsm_sconfreq(f); /* Send Configure-Request */ - TIMEOUT(fsm_timeout, (caddr_t) f, f->timeouttime); + GETCHAR(code, inp); + GETCHAR(id, inp); + GETSHORT(len, inp); + if (len < HEADERLEN) { + FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd illegal length.", + f->protocol)); + return; } - - if (f->callbacks->reqci) /* Check CI */ - code = (*f->callbacks->reqci)(f, inp, &len); - else if (len) - code = CONFREJ; /* Reject all CI */ - - len += HEADERLEN; /* add header length back on */ - - inp = inpacket; /* Reset to header */ - outp = outpacket_buf; /* get pointer to output buffer */ - MAKEHEADER(outp, f->protocol); /* paste in DLL header */ - BCOPY(inp, outp, len); /* copy input packet */ - PUTCHAR(code, outp); /* put in the code, id, and length*/ - PUTCHAR(id, outp); - PUTSHORT(len, outp); - output(f->unit, outpacket_buf, len + DLLHEADERLEN); /* send it out */ - - if (code == CONFACK) { - if (f->state == ACKRCVD) { - UNTIMEOUT(fsm_timeout, (caddr_t) f); /* Cancel timeout */ - if (f->callbacks->up) - (*f->callbacks->up)(f); /* Inform upper layers */ - f->state = OPEN; - } - else - f->state = ACKSENT; + if (len > l) { + FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd short packet.", + f->protocol)); + return; } - else { - if (f->state != ACKRCVD) - f->state = REQSENT; + len -= HEADERLEN; /* subtract header length */ + + if( f->state == INITIAL || f->state == STARTING ){ + FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd packet in state %d.", + f->protocol, f->state)); + return; } - return; - - case CONFACK: - fsm_rconfack(f, inp, id, len); - break; - - case CONFNAK: - fsm_rconfnak(f, inp, id, len); - break; - - case CONFREJ: - fsm_rconfrej(f, inp, id, len); - break; + + /* + * Action depends on code. + */ + switch (code) { + case CONFREQ: + fsm_rconfreq(f, id, inp, len); + break; - case TERMREQ: - fsm_rtermreq(f, id); - break; + case CONFACK: + fsm_rconfack(f, id, inp, len); + break; - case TERMACK: - fsm_rtermack(f); - break; + case CONFNAK: + case CONFREJ: + fsm_rconfnakrej(f, code, id, inp, len); + break; - case CODEREJ: - fsm_rcoderej(f, inp, len); - break; + case TERMREQ: + fsm_rtermreq(f, id); + break; - case PROTREJ: - fsm_rprotrej(f, inp, len); - break; + case TERMACK: + fsm_rtermack(f); + break; - case ECHOREQ: - FSMDEBUG((LOG_INFO, "lcp: Echo-Request, Rcvd id %d", id)); + case CODEREJ: + fsm_rcoderej(f, inp, len); + break; - switch (f->state) { - case CLOSED: - case LISTEN: - fsm_sdata(f, TERMACK, id, NULL, 0); - break; - - case OPEN: - inp = inpacket; /* Reset to header */ - outp = outpacket_buf; /* get pointer to output buffer */ - MAKEHEADER(outp, f->protocol); /* add DLL header */ - len += HEADERLEN; /* add header length */ - BCOPY(inp, outp, len); /* copy input packet to output buffer */ - PUTCHAR(ECHOREP, outp); /* set code to echo reply */ - PUTCHAR(id, outp); /* add in id */ - PUTSHORT(len, outp); /* and length */ - output(f->unit, outpacket_buf, len + DLLHEADERLEN); /* send it */ - return; + default: + if( !f->callbacks->extcode + || !(*f->callbacks->extcode)(f, code, id, inp, len) ) + fsm_sdata(f, CODEREJ, ++f->id, inpacket, len + HEADERLEN); + break; } - break; - - case ECHOREP: - case DISCREQ: - /* XXX Deliver to ECHOREQ sender? */ - break; - - default: - fsm_sdata(f, CODEREJ, ++f->id, inpacket, len + HEADERLEN); - break; - } - } /* - * fsm_rconfack - Receive Configure-Ack. + * fsm_rconfreq - Receive Configure-Request. */ static void - fsm_rconfack(f, inp, id, len) -fsm *f; -u_char *inp; -u_char id; -int len; +fsm_rconfreq(f, id, inp, len) + fsm *f; + u_char id; + u_char *inp; + int len; { - FSMDEBUG((LOG_INFO, "fsm_rconfack(%x): Rcvd id %d.", - f->protocol, id)) + u_char *outp; + int code, reject_if_disagree; - switch (f->state) { - case LISTEN: - case CLOSED: + FSMDEBUG((LOG_INFO, "fsm_rconfreq(%s): Rcvd id %d.", PROTO_NAME(f), id)); + switch( f->state ){ + case CLOSED: + /* Go away, we're closed */ fsm_sdata(f, TERMACK, id, NULL, 0); + return; + case CLOSING: + case STOPPING: + return; + + case OPENED: + /* Go down and restart negotiation */ + if( f->callbacks->down ) + (*f->callbacks->down)(f); /* Inform upper layers */ + fsm_sconfreq(f, 0); /* Send initial Configure-Request */ break; - case ACKRCVD: - case REQSENT: - if (id != f->reqid) /* Expected id? */ - break; /* Nope, toss... */ - if (f->callbacks->ackci && - (*f->callbacks->ackci)(f, inp, len)) /* Good ack? */ - f->state = ACKRCVD; - else - f->state = REQSENT; /* Wait for timeout to retransmit */ + case STOPPED: + /* Negotiation started by our peer */ + fsm_sconfreq(f, 0); /* Send initial Configure-Request */ + f->state = REQSENT; break; + } - case ACKSENT: - if (id != f->reqid) /* Expected id? */ - break; /* Nope, toss... */ - if (f->callbacks->ackci && - (*f->callbacks->ackci)(f, inp, len)) { /* Good ack? */ + /* + * Pass the requested configuration options + * to protocol-specific code for checking. + */ + if (f->callbacks->reqci){ /* Check CI */ + reject_if_disagree = (f->nakloops >= f->maxnakloops); + code = (*f->callbacks->reqci)(f, inp, &len, reject_if_disagree); + } else if (len) + code = CONFREJ; /* Reject all CI */ + + /* send the Ack, Nak or Rej to the peer */ + fsm_sdata(f, code, id, inp, len); + + if (code == CONFACK) { + if (f->state == ACKRCVD) { UNTIMEOUT(fsm_timeout, (caddr_t) f); /* Cancel timeout */ + f->state = OPENED; if (f->callbacks->up) (*f->callbacks->up)(f); /* Inform upper layers */ - f->state = OPEN; - } - else - f->state = REQSENT; /* Wait for timeout to retransmit */ - break; + } else + f->state = ACKSENT; + f->nakloops = 0; - case OPEN: - if (f->callbacks->down) - (*f->callbacks->down)(f); /* Inform upper layers */ - f->state = CLOSED; /* Only for a moment... */ - fsm_activeopen(f); /* Restart */ - break; + } else { + /* we sent CONFACK or CONFREJ */ + if (f->state != ACKRCVD) + f->state = REQSENT; + if( code == CONFNAK ) + ++f->nakloops; } } /* - * fsm_rconfnak - Receive Configure-Nak. + * fsm_rconfack - Receive Configure-Ack. */ static void - fsm_rconfnak(f, inp, id, len) -fsm *f; -u_char *inp; -u_char id; -int len; +fsm_rconfack(f, id, inp, len) + fsm *f; + int id; + u_char *inp; + int len; { - FSMDEBUG((LOG_INFO, "fsm_rconfnak(%x): Rcvd id %d.", - f->protocol, id)) + FSMDEBUG((LOG_INFO, "fsm_rconfack(%s): Rcvd id %d.", + PROTO_NAME(f), id)); + + if (id != f->reqid) /* Expected id? */ + return; /* Nope, toss... */ + if( !(f->callbacks->ackci? (*f->callbacks->ackci)(f, inp, len): (len == 0)) ){ + /* Ack is bad - ignore it */ + FSMDEBUG((LOG_INFO, "%s: received bad Ack (length %d)", + PROTO_NAME(f), len)); + return; + } switch (f->state) { - case LISTEN: - case CLOSED: + case CLOSED: + case STOPPED: fsm_sdata(f, TERMACK, id, NULL, 0); break; - case REQSENT: - case ACKSENT: - if (id != f->reqid) /* Expected id? */ - break; /* Nope, toss... */ - if (++f->nakloops > f->maxnakloops) { - FSMDEBUG((LOG_INFO, - "fsm_rconfnak(%x): Possible CONFNAK loop!", - f->protocol)) - break; /* Break the loop */ - } - UNTIMEOUT(fsm_timeout, (caddr_t) f); /* Cancel timeout */ - if (f->callbacks->nakci) - (*f->callbacks->nakci)(f, inp, len); - fsm_sconfreq(f); /* Send Configure-Request */ - TIMEOUT(fsm_timeout, (caddr_t) f, f->timeouttime); - ++f->retransmits; + case REQSENT: + f->state = ACKRCVD; + f->retransmits = f->maxconfreqtransmits; break; - case ACKRCVD: - f->state = REQSENT; /* Wait for timeout to retransmit */ + case ACKRCVD: + /* Huh? an extra Ack? oh well... */ + fsm_sconfreq(f, 0); + f->state = REQSENT; break; - case OPEN: + case ACKSENT: + UNTIMEOUT(fsm_timeout, (caddr_t) f); /* Cancel timeout */ + f->state = OPENED; + f->retransmits = f->maxconfreqtransmits; + if (f->callbacks->up) + (*f->callbacks->up)(f); /* Inform upper layers */ + break; + + case OPENED: + /* Go down and restart negotiation */ if (f->callbacks->down) (*f->callbacks->down)(f); /* Inform upper layers */ - f->state = CLOSED; /* Only for a moment... */ - fsm_activeopen(f); /* Restart */ + fsm_sconfreq(f, 0); /* Send initial Configure-Request */ + f->state = REQSENT; break; } } /* - * fsm_rconfrej - Receive Configure-Rej. + * fsm_rconfnakrej - Receive Configure-Nak or Configure-Reject. */ static void - fsm_rconfrej(f, inp, id, len) -fsm *f; -u_char *inp; -u_char id; -int len; +fsm_rconfnakrej(f, code, id, inp, len) + fsm *f; + int code, id; + u_char *inp; + int len; { - FSMDEBUG((LOG_INFO, "fsm_rconfrej(%x): Rcvd id %d.", - f->protocol, id)) + int (*proc)(); + + FSMDEBUG((LOG_INFO, "fsm_rconfnakrej(%s): Rcvd id %d.", + PROTO_NAME(f), id)); + + if (id != f->reqid) /* Expected id? */ + return; /* Nope, toss... */ + proc = (code == CONFNAK)? f->callbacks->nakci: f->callbacks->rejci; + if( !proc || !proc(f, inp, len) ){ + /* Nak/reject is bad - ignore it */ + FSMDEBUG((LOG_INFO, "%s: received bad %s (length %d)", + PROTO_NAME(f), (code==CONFNAK? "Nak": "reject"), len)); + return; + } switch (f->state) { - case LISTEN: - case CLOSED: + case CLOSED: + case STOPPED: fsm_sdata(f, TERMACK, id, NULL, 0); break; - case REQSENT: - case ACKSENT: - if (id != f->reqid) /* Expected id? */ - break; /* Nope, toss... */ - if (++f->nakloops > f->maxnakloops) - break; /* Break the loop */ + case REQSENT: + case ACKSENT: + /* They didn't agree to what we wanted - try another request */ UNTIMEOUT(fsm_timeout, (caddr_t) f); /* Cancel timeout */ - if (f->callbacks->rejci) - (*f->callbacks->rejci)(f, inp, len); - fsm_sconfreq(f); /* Send Configure-Request */ - TIMEOUT(fsm_timeout, (caddr_t) f, f->timeouttime); - ++f->retransmits; + fsm_sconfreq(f, 0); /* Send Configure-Request */ break; - case ACKRCVD: - f->state = REQSENT; /* Wait for timeout to retransmit */ + case ACKRCVD: + /* Got a Nak/reject when we had already had an Ack?? oh well... */ + fsm_sconfreq(f, 0); + f->state = REQSENT; break; - case OPEN: - f->state = CLOSED; /* Only for a moment... */ - fsm_activeopen(f); /* Restart */ + case OPENED: + /* Go down and restart negotiation */ + if (f->callbacks->down) + (*f->callbacks->down)(f); /* Inform upper layers */ + fsm_sconfreq(f, 0); /* Send initial Configure-Request */ + f->state = REQSENT; break; } } @@ -591,26 +549,27 @@ int len; * fsm_rtermreq - Receive Terminate-Req. */ static void - fsm_rtermreq(f, id) -fsm *f; -u_char id; +fsm_rtermreq(f, id) + fsm *f; + int id; { - FSMDEBUG((LOG_INFO, "fsm_rtermreq(%x): Rcvd id %d.", - f->protocol, id)) + FSMDEBUG((LOG_INFO, "fsm_rtermreq(%s): Rcvd id %d.", + PROTO_NAME(f), id)); fsm_sdata(f, TERMACK, id, NULL, 0); switch (f->state) { - case ACKRCVD: - case ACKSENT: + case ACKRCVD: + case ACKSENT: f->state = REQSENT; /* Start over but keep trying */ break; - case OPEN: + case OPENED: + syslog(LOG_INFO, "%s terminated at peer's request", PROTO_NAME(f)); if (f->callbacks->down) (*f->callbacks->down)(f); /* Inform upper layers */ - f->state = CLOSED; - if (f->callbacks->closed) - (*f->callbacks->closed)(f); /* Exit/restart/etc. */ + f->retransmits = 0; + f->state = STOPPING; + TIMEOUT(fsm_timeout, (caddr_t) f, f->timeouttime); break; } } @@ -620,25 +579,31 @@ u_char id; * fsm_rtermack - Receive Terminate-Ack. */ static void - fsm_rtermack(f) -fsm *f; +fsm_rtermack(f) + fsm *f; { - FSMDEBUG((LOG_INFO, "fsm_rtermack(%x).", f->protocol)) + FSMDEBUG((LOG_INFO, "fsm_rtermack(%s).", PROTO_NAME(f))); switch (f->state) { - case OPEN: - if (f->callbacks->down) - (*f->callbacks->down)(f); /* Inform upper layers */ + case CLOSING: f->state = CLOSED; - if (f->callbacks->closed) - (*f->callbacks->closed)(f); /* Exit/restart/etc. */ + if( f->callbacks->finished ) + (*f->callbacks->finished)(f); + break; + case STOPPING: + f->state = STOPPED; + if( f->callbacks->finished ) + (*f->callbacks->finished)(f); break; - case TERMSENT: - UNTIMEOUT(fsm_timeout, (caddr_t) f); /* Cancel timeout */ - f->state = CLOSED; - if (f->callbacks->closed) - (*f->callbacks->closed)(f); /* Exit/restart/etc. */ + case ACKRCVD: + f->state = REQSENT; + break; + + case OPENED: + if (f->callbacks->down) + (*f->callbacks->down)(f); /* Inform upper layers */ + fsm_sconfreq(f, 0); break; } } @@ -648,59 +613,77 @@ fsm *f; * fsm_rcoderej - Receive an Code-Reject. */ static void - fsm_rcoderej(f, inp, len) -fsm *f; -u_char *inp; -int len; +fsm_rcoderej(f, inp, len) + fsm *f; + u_char *inp; + int len; { - u_char code; + u_char code, id; - FSMDEBUG((LOG_INFO, "fsm_rcoderej(%x).", f->protocol)) + FSMDEBUG((LOG_INFO, "fsm_rcoderej(%s).", PROTO_NAME(f))); - if (len < sizeof (u_char)) { - FSMDEBUG((LOG_INFO, - "fsm_rcoderej: Rcvd short Code-Reject packet!")) + if (len < HEADERLEN) { + FSMDEBUG((LOG_INFO, "fsm_rcoderej: Rcvd short Code-Reject packet!")); return; } GETCHAR(code, inp); - FSMDEBUG((LOG_INFO, - "fsm_rcoderej: Rcvd Code-Reject for code %d!", - code)) + GETCHAR(id, inp); + syslog(LOG_WARNING, "%s: Rcvd Code-Reject for code %d, id %d", + PROTO_NAME(f), code, id); + + if( f->state == ACKRCVD ) + f->state = REQSENT; } /* - * fsm_rprotrej - Receive an Protocol-Reject. + * fsm_protreject - Peer doesn't speak this protocol. * - * Figure out which protocol is rejected and inform it. + * Treat this as a catastrophic error (RXJ-). */ -static void - fsm_rprotrej(f, inp, len) -fsm *f; -u_char *inp; -int len; +void +fsm_protreject(f) + fsm *f; { - u_short prot; + switch( f->state ){ + case CLOSING: + UNTIMEOUT(fsm_timeout, (caddr_t) f); /* Cancel timeout */ + /* fall through */ + case CLOSED: + f->state = CLOSED; + if( f->callbacks->finished ) + (*f->callbacks->finished)(f); + break; - FSMDEBUG((LOG_INFO, "fsm_rprotrej.")) + case STOPPING: + case REQSENT: + case ACKRCVD: + case ACKSENT: + UNTIMEOUT(fsm_timeout, (caddr_t) f); /* Cancel timeout */ + /* fall through */ + case STOPPED: + f->state = STOPPED; + if( f->callbacks->finished ) + (*f->callbacks->finished)(f); + break; - if (len < sizeof (u_short)) { - FSMDEBUG((LOG_INFO, - "fsm_rprotrej: Rcvd short Protocol-Reject packet!")) - return; - } - if (f->protocol != LCP) { /* Only valid for LCP */ - FSMDEBUG((LOG_INFO, - "fsm_rprotrej: Rcvd non-LCP Protocol-Reject!")) - return; - } + case OPENED: + if( f->callbacks->down ) + (*f->callbacks->down)(f); - GETSHORT(prot, inp); + /* Init restart counter, send Terminate-Request */ + f->retransmits = f->maxtermtransmits; + fsm_sdata(f, TERMREQ, f->reqid = ++f->id, NULL, 0); + TIMEOUT(fsm_timeout, (caddr_t) f, f->timeouttime); + --f->retransmits; + + f->state = STOPPING; + break; - FSMDEBUG((LOG_INFO, - "fsm_rprotrej: Rcvd Protocol-Reject packet for %x!", - prot)) - DEMUXPROTREJ(f->unit, prot); /* Inform protocol */ + default: + FSMDEBUG((LOG_INFO, "%s: Protocol-reject event in state %d!", + PROTO_NAME(f), f->state)); + } } @@ -708,58 +691,79 @@ int len; * fsm_sconfreq - Send a Configure-Request. */ static void - fsm_sconfreq(f) -fsm *f; +fsm_sconfreq(f, retransmit) + fsm *f; + int retransmit; { u_char *outp; - int outlen; + int outlen, cilen; - outlen = HEADERLEN + (f->callbacks->cilen ? (*f->callbacks->cilen)(f) : 0); - /* XXX Adjust outlen to MTU */ - outp = outpacket_buf; - MAKEHEADER(outp, f->protocol); + if( f->state != REQSENT && f->state != ACKRCVD && f->state != ACKSENT ){ + /* Not currently negotiating - reset options */ + if( f->callbacks->resetci ) + (*f->callbacks->resetci)(f); + f->nakloops = 0; + } - PUTCHAR(CONFREQ, outp); - PUTCHAR(f->reqid = ++f->id, outp); - PUTSHORT(outlen, outp); - if (f->callbacks->cilen && f->callbacks->addci) - (*f->callbacks->addci)(f, outp); - output(f->unit, outpacket_buf, outlen + DLLHEADERLEN); + if( !retransmit ){ + /* New request - reset retransmission counter, use new ID */ + f->retransmits = f->maxconfreqtransmits; + f->reqid = ++f->id; + } + + /* + * Make up the request packet + */ + if( f->callbacks->cilen && f->callbacks->addci ){ + cilen = (*f->callbacks->cilen)(f); + if( cilen > peer_mru[f->unit] - HEADERLEN ) + cilen = peer_mru[f->unit] - HEADERLEN; + outp = outpacket_buf + DLLHEADERLEN + HEADERLEN; + if (f->callbacks->addci) + (*f->callbacks->addci)(f, outp, &cilen); + } else + cilen = 0; + + /* send the request to our peer */ + fsm_sdata(f, CONFREQ, f->reqid, outp, cilen); + + /* start the retransmit timer */ + --f->retransmits; + TIMEOUT(fsm_timeout, (caddr_t) f, f->timeouttime); FSMDEBUG((LOG_INFO, "%s: sending Configure-Request, id %d", - proto_name(f->protocol), f->reqid)) + PROTO_NAME(f), f->reqid)); } /* * fsm_sdata - Send some data. * - * Used for Terminate-Request, Terminate-Ack, Code-Reject, Protocol-Reject, - * Echo-Request, and Discard-Request. + * Used for all packets sent to our peer by this module. */ void - fsm_sdata(f, code, id, data, datalen) -fsm *f; -u_char code, id; -u_char *data; -int datalen; +fsm_sdata(f, code, id, data, datalen) + fsm *f; + u_char code, id; + u_char *data; + int datalen; { u_char *outp; int outlen; /* Adjust length to be smaller than MTU */ - if (datalen > MTU - HEADERLEN) - datalen = MTU - HEADERLEN; - outlen = datalen + HEADERLEN; outp = outpacket_buf; + if (datalen > peer_mru[f->unit] - HEADERLEN) + datalen = peer_mru[f->unit] - HEADERLEN; + if (datalen && data != outp + DLLHEADERLEN + HEADERLEN) + BCOPY(data, outp + DLLHEADERLEN + HEADERLEN, datalen); + outlen = datalen + HEADERLEN; MAKEHEADER(outp, f->protocol); PUTCHAR(code, outp); PUTCHAR(id, outp); PUTSHORT(outlen, outp); - if (datalen) - BCOPY(data, outp, datalen); output(f->unit, outpacket_buf, outlen + DLLHEADERLEN); - FSMDEBUG((LOG_INFO, "fsm_sdata(%x): Sent code %d, id %d.", - f->protocol, code, id)) + FSMDEBUG((LOG_INFO, "fsm_sdata(%s): Sent code %d, id %d.", + PROTO_NAME(f), code, id)); } |