X-Git-Url: http://git.ozlabs.org/?p=ppp.git;a=blobdiff_plain;f=pppd%2Ffsm.c;h=c200cc3a84387cefc952bdd37bac6650bf32161d;hp=23d6773307474a4277045a284a5066584904d784;hb=1c8af01fd1c14975b6ea9d757578ccbcafd97abb;hpb=0b63a24d54ba4708c88e31bdd74b0145956c1478 diff --git a/pppd/fsm.c b/pppd/fsm.c index 23d6773..c200cc3 100644 --- a/pppd/fsm.c +++ b/pppd/fsm.c @@ -1,25 +1,46 @@ /* * fsm.c - {Link, IP} Control Protocol Finite State Machine. * - * Copyright (c) 1989 Carnegie Mellon University. - * All rights reserved. + * Copyright (c) 1984-2000 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. + * 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. */ -#ifndef lint -static char rcsid[] = "$Id: fsm.c,v 1.1 1993/11/11 03:54:25 paulus Exp $"; -#endif +#define RCSID "$Id: fsm.c,v 1.23 2004/11/13 02:28:15 paulus Exp $" /* * TODO: @@ -28,28 +49,26 @@ static char rcsid[] = "$Id: fsm.c,v 1.1 1993/11/11 03:54:25 paulus Exp $"; */ #include +#include #include -/*#include */ -#include -#include "ppp.h" #include "pppd.h" #include "fsm.h" -extern char *proto_name(); +static const char rcsid[] = RCSID; -static void fsm_timeout __ARGS((caddr_t)); -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_sconfreq __ARGS((fsm *, int)); +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[NPPP]; +int peer_mru[NUM_PPP]; /* @@ -68,6 +87,7 @@ fsm_init(f) f->maxconfreqtransmits = DEFMAXCONFREQS; f->maxtermtransmits = DEFMAXTERMREQS; f->maxnakloops = DEFMAXNAKLOOPS; + f->term_reason_len = 0; } @@ -94,8 +114,7 @@ fsm_lowerup(f) break; default: - FSMDEBUG((LOG_INFO, "%s: Up event in state %d!", - PROTO_NAME(f), f->state)); + FSMDEBUG(("%s: Up event in state %d!", PROTO_NAME(f), f->state)); } } @@ -122,7 +141,7 @@ fsm_lowerdown(f) case CLOSING: f->state = INITIAL; - UNTIMEOUT(fsm_timeout, (caddr_t) f); /* Cancel timeout */ + UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ break; case STOPPING: @@ -130,7 +149,7 @@ fsm_lowerdown(f) case ACKRCVD: case ACKSENT: f->state = STARTING; - UNTIMEOUT(fsm_timeout, (caddr_t) f); /* Cancel timeout */ + UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ break; case OPENED: @@ -140,8 +159,7 @@ fsm_lowerdown(f) break; default: - FSMDEBUG((LOG_INFO, "%s: Down event in state %d!", - PROTO_NAME(f), f->state)); + FSMDEBUG(("%s: Down event in state %d!", PROTO_NAME(f), f->state)); } } @@ -183,6 +201,44 @@ fsm_open(f) } } +/* + * 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 void +terminate_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. @@ -191,9 +247,12 @@ fsm_open(f) * the CLOSED state. */ void -fsm_close(f) +fsm_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; @@ -209,18 +268,7 @@ fsm_close(f) 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 */ - - /* 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; + terminate_layer(f, CLOSING); break; } } @@ -231,7 +279,7 @@ fsm_close(f) */ static void fsm_timeout(arg) - caddr_t arg; + void *arg; { fsm *f = (fsm *) arg; @@ -247,8 +295,9 @@ fsm_timeout(arg) (*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); + 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; @@ -257,8 +306,7 @@ fsm_timeout(arg) case ACKRCVD: case ACKSENT: if (f->retransmits <= 0) { - syslog(LOG_WARNING, "%s: timeout sending Config-Requests", - PROTO_NAME(f)); + 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); @@ -274,8 +322,7 @@ fsm_timeout(arg) break; default: - FSMDEBUG((LOG_INFO, "%s: Timeout event in state %d!", - PROTO_NAME(f), f->state)); + FSMDEBUG(("%s: Timeout event in state %d!", PROTO_NAME(f), f->state)); } } @@ -289,7 +336,7 @@ fsm_input(f, inpacket, l) u_char *inpacket; int l; { - u_char *inp, *outp; + u_char *inp; u_char code, id; int len; @@ -299,27 +346,24 @@ fsm_input(f, inpacket, l) */ inp = inpacket; if (l < HEADERLEN) { - FSMDEBUG((LOG_WARNING, "fsm_input(%x): Rcvd short header.", - f->protocol)); + FSMDEBUG(("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)); + FSMDEBUG(("fsm_input(%x): Rcvd illegal length.", f->protocol)); return; } if (len > l) { - FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd short packet.", - f->protocol)); + FSMDEBUG(("fsm_input(%x): Rcvd short packet.", f->protocol)); return; } len -= HEADERLEN; /* subtract header length */ if( f->state == INITIAL || f->state == STARTING ){ - FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd packet in state %d.", + FSMDEBUG(("fsm_input(%x): Rcvd packet in state %d.", f->protocol, f->state)); return; } @@ -342,7 +386,7 @@ fsm_input(f, inpacket, l) break; case TERMREQ: - fsm_rtermreq(f, id); + fsm_rtermreq(f, id, inp, len); break; case TERMACK: @@ -372,10 +416,8 @@ fsm_rconfreq(f, id, inp, len) u_char *inp; int len; { - u_char *outp; int code, reject_if_disagree; - FSMDEBUG((LOG_INFO, "fsm_rconfreq(%s): Rcvd id %d.", PROTO_NAME(f), id)); switch( f->state ){ case CLOSED: /* Go away, we're closed */ @@ -390,6 +432,7 @@ fsm_rconfreq(f, id, inp, len) if( f->callbacks->down ) (*f->callbacks->down)(f); /* Inform upper layers */ fsm_sconfreq(f, 0); /* Send initial Configure-Request */ + f->state = REQSENT; break; case STOPPED: @@ -408,13 +451,15 @@ fsm_rconfreq(f, id, inp, len) code = (*f->callbacks->reqci)(f, inp, &len, reject_if_disagree); } else if (len) code = CONFREJ; /* Reject all CI */ + else + code = CONFACK; /* 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 */ + UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ f->state = OPENED; if (f->callbacks->up) (*f->callbacks->up)(f); /* Inform upper layers */ @@ -442,17 +487,16 @@ fsm_rconfack(f, id, inp, len) u_char *inp; int len; { - 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)) ){ + if (id != f->reqid || f->seen_ack) /* 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)); + error("Received bad configure-ack: %P", inp, len); return; } + f->seen_ack = 1; + f->rnakloops = 0; switch (f->state) { case CLOSED: @@ -466,13 +510,14 @@ fsm_rconfack(f, id, inp, len) break; case ACKRCVD: - /* Huh? an extra Ack? oh well... */ + /* Huh? an extra valid Ack? oh well... */ + UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ fsm_sconfreq(f, 0); f->state = REQSENT; break; case ACKSENT: - UNTIMEOUT(fsm_timeout, (caddr_t) f); /* Cancel timeout */ + UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ f->state = OPENED; f->retransmits = f->maxconfreqtransmits; if (f->callbacks->up) @@ -500,21 +545,31 @@ fsm_rconfnakrej(f, code, id, inp, len) u_char *inp; int len; { - 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; + int ret; + int treat_as_reject; + + if (id != f->reqid || f->seen_ack) /* Expected id? */ + return; /* Nope, toss... */ + + if (code == CONFNAK) { + ++f->rnakloops; + treat_as_reject = (f->rnakloops >= f->maxnakloops); + if (f->callbacks->nakci == NULL + || !(ret = f->callbacks->nakci(f, inp, len, treat_as_reject))) { + error("Received bad configure-nak: %P", inp, len); + return; + } + } else { + f->rnakloops = 0; + if (f->callbacks->rejci == NULL + || !(ret = f->callbacks->rejci(f, inp, len))) { + error("Received bad configure-rej: %P", inp, len); + return; + } } + f->seen_ack = 1; + switch (f->state) { case CLOSED: case STOPPED: @@ -524,12 +579,16 @@ fsm_rconfnakrej(f, code, id, inp, len) case REQSENT: case ACKSENT: /* They didn't agree to what we wanted - try another request */ - UNTIMEOUT(fsm_timeout, (caddr_t) f); /* Cancel timeout */ - fsm_sconfreq(f, 0); /* Send Configure-Request */ + UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ + if (ret < 0) + f->state = STOPPED; /* kludge for stopping CCP */ + else + fsm_sconfreq(f, 0); /* Send Configure-Request */ break; case ACKRCVD: /* Got a Nak/reject when we had already had an Ack?? oh well... */ + UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ fsm_sconfreq(f, 0); f->state = REQSENT; break; @@ -549,14 +608,12 @@ fsm_rconfnakrej(f, code, id, inp, len) * fsm_rtermreq - Receive Terminate-Req. */ static void -fsm_rtermreq(f, id) +fsm_rtermreq(f, id, p, len) fsm *f; int id; + u_char *p; + int len; { - 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: @@ -564,14 +621,19 @@ fsm_rtermreq(f, id) break; 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 */ + if (len > 0) { + info("%s terminated by peer (%0.*v)", PROTO_NAME(f), len, p); + } else + info("%s terminated by peer", PROTO_NAME(f)); f->retransmits = 0; f->state = STOPPING; - TIMEOUT(fsm_timeout, (caddr_t) f, f->timeouttime); + if (f->callbacks->down) + (*f->callbacks->down)(f); /* Inform upper layers */ + TIMEOUT(fsm_timeout, f, f->timeouttime); break; } + + fsm_sdata(f, TERMACK, id, NULL, 0); } @@ -582,15 +644,15 @@ static void fsm_rtermack(f) fsm *f; { - FSMDEBUG((LOG_INFO, "fsm_rtermack(%s).", PROTO_NAME(f))); - switch (f->state) { case CLOSING: + UNTIMEOUT(fsm_timeout, f); f->state = CLOSED; if( f->callbacks->finished ) (*f->callbacks->finished)(f); break; case STOPPING: + UNTIMEOUT(fsm_timeout, f); f->state = STOPPED; if( f->callbacks->finished ) (*f->callbacks->finished)(f); @@ -604,6 +666,7 @@ fsm_rtermack(f) if (f->callbacks->down) (*f->callbacks->down)(f); /* Inform upper layers */ fsm_sconfreq(f, 0); + f->state = REQSENT; break; } } @@ -620,16 +683,13 @@ fsm_rcoderej(f, inp, len) { u_char code, id; - FSMDEBUG((LOG_INFO, "fsm_rcoderej(%s).", PROTO_NAME(f))); - if (len < HEADERLEN) { - FSMDEBUG((LOG_INFO, "fsm_rcoderej: Rcvd short Code-Reject packet!")); + FSMDEBUG(("fsm_rcoderej: Rcvd short Code-Reject packet!")); return; } GETCHAR(code, inp); GETCHAR(id, inp); - syslog(LOG_WARNING, "%s: Rcvd Code-Reject for code %d, id %d", - PROTO_NAME(f), code, id); + warn("%s: Rcvd Code-Reject for code %d, id %d", PROTO_NAME(f), code, id); if( f->state == ACKRCVD ) f->state = REQSENT; @@ -647,7 +707,7 @@ fsm_protreject(f) { switch( f->state ){ case CLOSING: - UNTIMEOUT(fsm_timeout, (caddr_t) f); /* Cancel timeout */ + UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ /* fall through */ case CLOSED: f->state = CLOSED; @@ -659,7 +719,7 @@ fsm_protreject(f) case REQSENT: case ACKRCVD: case ACKSENT: - UNTIMEOUT(fsm_timeout, (caddr_t) f); /* Cancel timeout */ + UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ /* fall through */ case STOPPED: f->state = STOPPED; @@ -668,20 +728,11 @@ fsm_protreject(f) break; case OPENED: - if( f->callbacks->down ) - (*f->callbacks->down)(f); - - /* 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; + terminate_layer(f, STOPPING); break; default: - FSMDEBUG((LOG_INFO, "%s: Protocol-reject event in state %d!", + FSMDEBUG(("%s: Protocol-reject event in state %d!", PROTO_NAME(f), f->state)); } } @@ -696,13 +747,14 @@ fsm_sconfreq(f, retransmit) int retransmit; { u_char *outp; - int outlen, cilen; + int cilen; 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; + f->rnakloops = 0; } if( !retransmit ){ @@ -711,14 +763,16 @@ fsm_sconfreq(f, retransmit) f->reqid = ++f->id; } + f->seen_ack = 0; + /* * Make up the request packet */ + outp = outpacket_buf + PPP_HDRLEN + HEADERLEN; 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 @@ -729,10 +783,7 @@ fsm_sconfreq(f, retransmit) /* 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), f->reqid)); + TIMEOUT(fsm_timeout, f, f->timeouttime); } @@ -755,15 +806,12 @@ fsm_sdata(f, code, id, data, datalen) 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); + 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); - output(f->unit, outpacket_buf, outlen + DLLHEADERLEN); - - FSMDEBUG((LOG_INFO, "fsm_sdata(%s): Sent code %d, id %d.", - PROTO_NAME(f), code, id)); + output(f->unit, outpacket_buf, outlen + PPP_HDRLEN); }