Bonjour/Zerconf library

Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers fsm.c Source File

fsm.c

00001 /*****************************************************************************
00002 * fsm.c - Network Control Protocol Finite State Machine program file.
00003 *
00004 * Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
00005 * portions Copyright (c) 1997 by Global Election Systems Inc.
00006 *
00007 * The authors hereby grant permission to use, copy, modify, distribute,
00008 * and license this software and its documentation for any purpose, provided
00009 * that existing copyright notices are retained in all copies and that this
00010 * notice and the following disclaimer are included verbatim in any 
00011 * distributions. No written agreement, license, or royalty fee is required
00012 * for any of the authorized uses.
00013 *
00014 * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR
00015 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00016 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
00017 * IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00018 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00019 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00020 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00021 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00022 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00023 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00024 *
00025 ******************************************************************************
00026 * REVISION HISTORY
00027 *
00028 * 03-01-01 Marc Boucher <marc@mbsi.ca>
00029 *   Ported to lwIP.
00030 * 97-12-01 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.
00031 *   Original based on BSD fsm.c.
00032 *****************************************************************************/
00033 /*
00034  * fsm.c - {Link, IP} Control Protocol Finite State Machine.
00035  *
00036  * Copyright (c) 1989 Carnegie Mellon University.
00037  * All rights reserved.
00038  *
00039  * Redistribution and use in source and binary forms are permitted
00040  * provided that the above copyright notice and this paragraph are
00041  * duplicated in all such forms and that any documentation,
00042  * advertising materials, and other materials related to such
00043  * distribution and use acknowledge that the software was developed
00044  * by Carnegie Mellon University.  The name of the
00045  * University may not be used to endorse or promote products derived
00046  * from this software without specific prior written permission.
00047  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
00048  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
00049  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00050  */
00051 
00052 /*
00053  * TODO:
00054  * Randomize fsm id on link/init.
00055  * Deal with variable outgoing MTU.
00056  */
00057 
00058 #include "lwip/opt.h"
00059 
00060 #if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */
00061 
00062 #include "ppp.h"
00063 #include "pppdebug.h"
00064 
00065 #include "fsm.h"
00066 
00067 #include <string.h>
00068 
00069 #if PPP_DEBUG
00070 static const char *ppperr_strerr[] = {
00071            "LS_INITIAL",  /* LS_INITIAL  0 */
00072            "LS_STARTING", /* LS_STARTING 1 */
00073            "LS_CLOSED",   /* LS_CLOSED   2 */
00074            "LS_STOPPED",  /* LS_STOPPED  3 */
00075            "LS_CLOSING",  /* LS_CLOSING  4 */
00076            "LS_STOPPING", /* LS_STOPPING 5 */
00077            "LS_REQSENT",  /* LS_REQSENT  6 */
00078            "LS_ACKRCVD",  /* LS_ACKRCVD  7 */
00079            "LS_ACKSENT",  /* LS_ACKSENT  8 */
00080            "LS_OPENED"    /* LS_OPENED   9 */
00081 };
00082 #endif /* PPP_DEBUG */
00083 
00084 static void fsm_timeout (void *);
00085 static void fsm_rconfreq (fsm *, u_char, u_char *, int);
00086 static void fsm_rconfack (fsm *, int, u_char *, int);
00087 static void fsm_rconfnakrej (fsm *, int, int, u_char *, int);
00088 static void fsm_rtermreq (fsm *, int, u_char *, int);
00089 static void fsm_rtermack (fsm *);
00090 static void fsm_rcoderej (fsm *, u_char *, int);
00091 static void fsm_sconfreq (fsm *, int);
00092 
00093 #define PROTO_NAME(f) ((f)->callbacks->proto_name)
00094 
00095 int peer_mru[NUM_PPP];
00096 
00097 
00098 /*
00099  * fsm_init - Initialize fsm.
00100  *
00101  * Initialize fsm state.
00102  */
00103 void
00104 fsm_init(fsm *f)
00105 {
00106   f->state = LS_INITIAL;
00107   f->flags = 0;
00108   f->id = 0;        /* XXX Start with random id? */
00109   f->timeouttime = FSM_DEFTIMEOUT;
00110   f->maxconfreqtransmits = FSM_DEFMAXCONFREQS;
00111   f->maxtermtransmits = FSM_DEFMAXTERMREQS;
00112   f->maxnakloops = FSM_DEFMAXNAKLOOPS;
00113   f->term_reason_len = 0;
00114 }
00115 
00116 
00117 /*
00118  * fsm_lowerup - The lower layer is up.
00119  */
00120 void
00121 fsm_lowerup(fsm *f)
00122 {
00123   #if PPP_DEBUG
00124   int oldState = f->state;
00125   
00126   LWIP_UNUSED_ARG(oldState);
00127   #endif
00128 
00129   switch( f->state ) {
00130     case LS_INITIAL:
00131       f->state = LS_CLOSED;
00132       break;
00133 
00134     case LS_STARTING:
00135       if( f->flags & OPT_SILENT ) {
00136         f->state = LS_STOPPED;
00137       } else {
00138         /* Send an initial configure-request */
00139         fsm_sconfreq(f, 0);
00140         f->state = LS_REQSENT;
00141       }
00142     break;
00143 
00144     default:
00145       FSMDEBUG(LOG_INFO, ("%s: Up event in state %d (%s)!\n",
00146           PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
00147   }
00148 
00149   FSMDEBUG(LOG_INFO, ("%s: lowerup state %d (%s) -> %d (%s)\n",
00150       PROTO_NAME(f), oldState, ppperr_strerr[oldState], f->state, ppperr_strerr[f->state]));
00151 }
00152 
00153 
00154 /*
00155  * fsm_lowerdown - The lower layer is down.
00156  *
00157  * Cancel all timeouts and inform upper layers.
00158  */
00159 void
00160 fsm_lowerdown(fsm *f)
00161 {
00162   #if PPP_DEBUG
00163   int oldState = f->state;
00164 
00165   LWIP_UNUSED_ARG(oldState);
00166   #endif
00167 
00168   switch( f->state ) {
00169     case LS_CLOSED:
00170       f->state = LS_INITIAL;
00171       break;
00172 
00173     case LS_STOPPED:
00174       f->state = LS_STARTING;
00175       if( f->callbacks->starting ) {
00176         (*f->callbacks->starting)(f);
00177       }
00178       break;
00179 
00180     case LS_CLOSING:
00181       f->state = LS_INITIAL;
00182       UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */
00183       break;
00184 
00185     case LS_STOPPING:
00186     case LS_REQSENT:
00187     case LS_ACKRCVD:
00188     case LS_ACKSENT:
00189       f->state = LS_STARTING;
00190       UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */
00191       break;
00192 
00193     case LS_OPENED:
00194       if( f->callbacks->down ) {
00195         (*f->callbacks->down)(f);
00196       }
00197       f->state = LS_STARTING;
00198       break;
00199 
00200     default:
00201       FSMDEBUG(LOG_INFO, ("%s: Down event in state %d (%s)!\n",
00202           PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
00203   }
00204 
00205   FSMDEBUG(LOG_INFO, ("%s: lowerdown state %d (%s) -> %d (%s)\n",
00206       PROTO_NAME(f), oldState, ppperr_strerr[oldState], f->state, ppperr_strerr[f->state]));
00207 }
00208 
00209 
00210 /*
00211  * fsm_open - Link is allowed to come up.
00212  */
00213 void
00214 fsm_open(fsm *f)
00215 {
00216   #if PPP_DEBUG
00217   int oldState = f->state;
00218 
00219   LWIP_UNUSED_ARG(oldState);
00220   #endif
00221 
00222   switch( f->state ) {
00223     case LS_INITIAL:
00224       f->state = LS_STARTING;
00225       if( f->callbacks->starting ) {
00226         (*f->callbacks->starting)(f);
00227       }
00228       break;
00229 
00230     case LS_CLOSED:
00231       if( f->flags & OPT_SILENT ) {
00232         f->state = LS_STOPPED;
00233       } else {
00234         /* Send an initial configure-request */
00235         fsm_sconfreq(f, 0);
00236         f->state = LS_REQSENT;
00237       }
00238       break;
00239   
00240     case LS_CLOSING:
00241       f->state = LS_STOPPING;
00242       /* fall through */
00243     case LS_STOPPED:
00244     case LS_OPENED:
00245       if( f->flags & OPT_RESTART ) {
00246         fsm_lowerdown(f);
00247         fsm_lowerup(f);
00248       }
00249       break;
00250   }
00251 
00252   FSMDEBUG(LOG_INFO, ("%s: open state %d (%s) -> %d (%s)\n",
00253       PROTO_NAME(f), oldState, ppperr_strerr[oldState], f->state, ppperr_strerr[f->state]));
00254 }
00255 
00256 #if 0 /* backport pppd 2.4.4b1; */
00257 /*
00258  * terminate_layer - Start process of shutting down the FSM
00259  *
00260  * Cancel any timeout running, notify upper layers we're done, and
00261  * send a terminate-request message as configured.
00262  */
00263 static void
00264 terminate_layer(fsm *f, int nextstate)
00265 {
00266   /* @todo */
00267 }
00268 #endif
00269 
00270 /*
00271  * fsm_close - Start closing connection.
00272  *
00273  * Cancel timeouts and either initiate close or possibly go directly to
00274  * the LS_CLOSED state.
00275  */
00276 void
00277 fsm_close(fsm *f, char *reason)
00278 {
00279   #if PPP_DEBUG
00280   int oldState = f->state;
00281 
00282   LWIP_UNUSED_ARG(oldState);
00283   #endif
00284 
00285   f->term_reason = reason;
00286   f->term_reason_len = (reason == NULL ? 0 : (int)strlen(reason));
00287   switch( f->state ) {
00288     case LS_STARTING:
00289       f->state = LS_INITIAL;
00290       break;
00291     case LS_STOPPED:
00292       f->state = LS_CLOSED;
00293       break;
00294     case LS_STOPPING:
00295       f->state = LS_CLOSING;
00296       break;
00297 
00298     case LS_REQSENT:
00299     case LS_ACKRCVD:
00300     case LS_ACKSENT:
00301     case LS_OPENED:
00302       if( f->state != LS_OPENED ) {
00303         UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */
00304       } else if( f->callbacks->down ) {
00305         (*f->callbacks->down)(f);  /* Inform upper layers we're down */
00306       }
00307       /* Init restart counter, send Terminate-Request */
00308       f->retransmits = f->maxtermtransmits;
00309       fsm_sdata(f, TERMREQ, f->reqid = ++f->id,
00310             (u_char *) f->term_reason, f->term_reason_len);
00311       TIMEOUT(fsm_timeout, f, f->timeouttime);
00312       --f->retransmits;
00313 
00314       f->state = LS_CLOSING;
00315       break;
00316   }
00317 
00318   FSMDEBUG(LOG_INFO, ("%s: close reason=%s state %d (%s) -> %d (%s)\n",
00319       PROTO_NAME(f), reason, oldState, ppperr_strerr[oldState], f->state, ppperr_strerr[f->state]));
00320 }
00321 
00322 
00323 /*
00324  * fsm_timeout - Timeout expired.
00325  */
00326 static void
00327 fsm_timeout(void *arg)
00328 {
00329   fsm *f = (fsm *) arg;
00330 
00331   switch (f->state) {
00332     case LS_CLOSING:
00333     case LS_STOPPING:
00334       if( f->retransmits <= 0 ) {
00335         FSMDEBUG(LOG_WARNING, ("%s: timeout sending Terminate-Request state=%d (%s)\n",
00336              PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
00337         /*
00338          * We've waited for an ack long enough.  Peer probably heard us.
00339          */
00340         f->state = (f->state == LS_CLOSING)? LS_CLOSED: LS_STOPPED;
00341         if( f->callbacks->finished ) {
00342           (*f->callbacks->finished)(f);
00343         }
00344       } else {
00345         FSMDEBUG(LOG_WARNING, ("%s: timeout resending Terminate-Requests state=%d (%s)\n",
00346              PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
00347         /* Send Terminate-Request */
00348         fsm_sdata(f, TERMREQ, f->reqid = ++f->id,
00349             (u_char *) f->term_reason, f->term_reason_len);
00350         TIMEOUT(fsm_timeout, f, f->timeouttime);
00351         --f->retransmits;
00352       }
00353       break;
00354 
00355     case LS_REQSENT:
00356     case LS_ACKRCVD:
00357     case LS_ACKSENT:
00358       if (f->retransmits <= 0) {
00359         FSMDEBUG(LOG_WARNING, ("%s: timeout sending Config-Requests state=%d (%s)\n",
00360          PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
00361         f->state = LS_STOPPED;
00362         if( (f->flags & OPT_PASSIVE) == 0 && f->callbacks->finished ) {
00363           (*f->callbacks->finished)(f);
00364         }
00365       } else {
00366         FSMDEBUG(LOG_WARNING, ("%s: timeout resending Config-Request state=%d (%s)\n",
00367          PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
00368         /* Retransmit the configure-request */
00369         if (f->callbacks->retransmit) {
00370           (*f->callbacks->retransmit)(f);
00371         }
00372         fsm_sconfreq(f, 1);    /* Re-send Configure-Request */
00373         if( f->state == LS_ACKRCVD ) {
00374           f->state = LS_REQSENT;
00375         }
00376       }
00377       break;
00378 
00379     default:
00380       FSMDEBUG(LOG_INFO, ("%s: UNHANDLED timeout event in state %d (%s)!\n",
00381           PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
00382   }
00383 }
00384 
00385 
00386 /*
00387  * fsm_input - Input packet.
00388  */
00389 void
00390 fsm_input(fsm *f, u_char *inpacket, int l)
00391 {
00392   u_char *inp = inpacket;
00393   u_char code, id;
00394   int len;
00395 
00396   /*
00397   * Parse header (code, id and length).
00398   * If packet too short, drop it.
00399   */
00400   if (l < HEADERLEN) {
00401     FSMDEBUG(LOG_WARNING, ("fsm_input(%x): Rcvd short header.\n",
00402           f->protocol));
00403     return;
00404   }
00405   GETCHAR(code, inp);
00406   GETCHAR(id, inp);
00407   GETSHORT(len, inp);
00408   if (len < HEADERLEN) {
00409     FSMDEBUG(LOG_INFO, ("fsm_input(%x): Rcvd illegal length.\n",
00410         f->protocol));
00411     return;
00412   }
00413   if (len > l) {
00414     FSMDEBUG(LOG_INFO, ("fsm_input(%x): Rcvd short packet.\n",
00415         f->protocol));
00416     return;
00417   }
00418   len -= HEADERLEN;    /* subtract header length */
00419 
00420   if( f->state == LS_INITIAL || f->state == LS_STARTING ) {
00421     FSMDEBUG(LOG_INFO, ("fsm_input(%x): Rcvd packet in state %d (%s).\n",
00422         f->protocol, f->state, ppperr_strerr[f->state]));
00423     return;
00424   }
00425   FSMDEBUG(LOG_INFO, ("fsm_input(%s):%d,%d,%d\n", PROTO_NAME(f), code, id, l));
00426   /*
00427    * Action depends on code.
00428    */
00429   switch (code) {
00430     case CONFREQ:
00431       fsm_rconfreq(f, id, inp, len);
00432       break;
00433     
00434     case CONFACK:
00435       fsm_rconfack(f, id, inp, len);
00436       break;
00437     
00438     case CONFNAK:
00439     case CONFREJ:
00440       fsm_rconfnakrej(f, code, id, inp, len);
00441       break;
00442     
00443     case TERMREQ:
00444       fsm_rtermreq(f, id, inp, len);
00445       break;
00446     
00447     case TERMACK:
00448       fsm_rtermack(f);
00449       break;
00450     
00451     case CODEREJ:
00452       fsm_rcoderej(f, inp, len);
00453       break;
00454     
00455     default:
00456       FSMDEBUG(LOG_INFO, ("fsm_input(%s): default: \n", PROTO_NAME(f)));
00457       if( !f->callbacks->extcode ||
00458           !(*f->callbacks->extcode)(f, code, id, inp, len) ) {
00459         fsm_sdata(f, CODEREJ, ++f->id, inpacket, len + HEADERLEN);
00460       }
00461       break;
00462   }
00463 }
00464 
00465 
00466 /*
00467  * fsm_rconfreq - Receive Configure-Request.
00468  */
00469 static void
00470 fsm_rconfreq(fsm *f, u_char id, u_char *inp, int len)
00471 {
00472   int code, reject_if_disagree;
00473 
00474   FSMDEBUG(LOG_INFO, ("fsm_rconfreq(%s): Rcvd id %d state=%d (%s)\n", 
00475         PROTO_NAME(f), id, f->state, ppperr_strerr[f->state]));
00476   switch( f->state ) {
00477     case LS_CLOSED:
00478       /* Go away, we're closed */
00479       fsm_sdata(f, TERMACK, id, NULL, 0);
00480       return;
00481     case LS_CLOSING:
00482     case LS_STOPPING:
00483       return;
00484 
00485     case LS_OPENED:
00486       /* Go down and restart negotiation */
00487       if( f->callbacks->down ) {
00488         (*f->callbacks->down)(f);  /* Inform upper layers */
00489       }
00490       fsm_sconfreq(f, 0);    /* Send initial Configure-Request */
00491       break;
00492 
00493     case LS_STOPPED:
00494       /* Negotiation started by our peer */
00495       fsm_sconfreq(f, 0);    /* Send initial Configure-Request */
00496       f->state = LS_REQSENT;
00497       break;
00498   }
00499   
00500   /*
00501   * Pass the requested configuration options
00502   * to protocol-specific code for checking.
00503   */
00504   if (f->callbacks->reqci) {    /* Check CI */
00505     reject_if_disagree = (f->nakloops >= f->maxnakloops);
00506     code = (*f->callbacks->reqci)(f, inp, &len, reject_if_disagree);
00507   } else if (len) {
00508     code = CONFREJ;      /* Reject all CI */
00509   } else {
00510     code = CONFACK;
00511   }
00512   
00513   /* send the Ack, Nak or Rej to the peer */
00514   fsm_sdata(f, (u_char)code, id, inp, len);
00515   
00516   if (code == CONFACK) {
00517     if (f->state == LS_ACKRCVD) {
00518       UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */
00519       f->state = LS_OPENED;
00520       if (f->callbacks->up) {
00521         (*f->callbacks->up)(f);  /* Inform upper layers */
00522       }
00523     } else {
00524       f->state = LS_ACKSENT;
00525     }
00526     f->nakloops = 0;
00527   } else {
00528     /* we sent CONFACK or CONFREJ */
00529     if (f->state != LS_ACKRCVD) {
00530       f->state = LS_REQSENT;
00531     }
00532     if( code == CONFNAK ) {
00533       ++f->nakloops;
00534     }
00535   }
00536 }
00537 
00538 
00539 /*
00540  * fsm_rconfack - Receive Configure-Ack.
00541  */
00542 static void
00543 fsm_rconfack(fsm *f, int id, u_char *inp, int len)
00544 {
00545   FSMDEBUG(LOG_INFO, ("fsm_rconfack(%s): Rcvd id %d state=%d (%s)\n",
00546         PROTO_NAME(f), id, f->state, ppperr_strerr[f->state]));
00547   
00548   if (id != f->reqid || f->seen_ack) {   /* Expected id? */
00549     return; /* Nope, toss... */
00550   }
00551   if( !(f->callbacks->ackci? (*f->callbacks->ackci)(f, inp, len): (len == 0)) ) {
00552     /* Ack is bad - ignore it */
00553     FSMDEBUG(LOG_INFO, ("%s: received bad Ack (length %d)\n",
00554           PROTO_NAME(f), len));
00555     return;
00556   }
00557   f->seen_ack = 1;
00558   
00559   switch (f->state) {
00560     case LS_CLOSED:
00561     case LS_STOPPED:
00562       fsm_sdata(f, TERMACK, (u_char)id, NULL, 0);
00563       break;
00564     
00565     case LS_REQSENT:
00566       f->state = LS_ACKRCVD;
00567       f->retransmits = f->maxconfreqtransmits;
00568       break;
00569     
00570     case LS_ACKRCVD:
00571       /* Huh? an extra valid Ack? oh well... */
00572       UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */
00573       fsm_sconfreq(f, 0);
00574       f->state = LS_REQSENT;
00575       break;
00576     
00577     case LS_ACKSENT:
00578       UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */
00579       f->state = LS_OPENED;
00580       f->retransmits = f->maxconfreqtransmits;
00581       if (f->callbacks->up) {
00582         (*f->callbacks->up)(f);  /* Inform upper layers */
00583       }
00584       break;
00585     
00586     case LS_OPENED:
00587       /* Go down and restart negotiation */
00588       if (f->callbacks->down) {
00589         (*f->callbacks->down)(f);  /* Inform upper layers */
00590       }
00591       fsm_sconfreq(f, 0);    /* Send initial Configure-Request */
00592       f->state = LS_REQSENT;
00593       break;
00594   }
00595 }
00596 
00597 
00598 /*
00599  * fsm_rconfnakrej - Receive Configure-Nak or Configure-Reject.
00600  */
00601 static void
00602 fsm_rconfnakrej(fsm *f, int code, int id, u_char *inp, int len)
00603 {
00604   int (*proc) (fsm *, u_char *, int);
00605   int ret;
00606 
00607   FSMDEBUG(LOG_INFO, ("fsm_rconfnakrej(%s): Rcvd id %d state=%d (%s)\n",
00608         PROTO_NAME(f), id, f->state, ppperr_strerr[f->state]));
00609 
00610   if (id != f->reqid || f->seen_ack) { /* Expected id? */
00611     return;        /* Nope, toss... */
00612   }
00613   proc = (code == CONFNAK)? f->callbacks->nakci: f->callbacks->rejci;
00614   if (!proc || !((ret = proc(f, inp, len)))) {
00615     /* Nak/reject is bad - ignore it */
00616     FSMDEBUG(LOG_INFO, ("%s: received bad %s (length %d)\n",
00617           PROTO_NAME(f), (code==CONFNAK? "Nak": "reject"), len));
00618     return;
00619   }
00620   f->seen_ack = 1;
00621 
00622   switch (f->state) {
00623     case LS_CLOSED:
00624     case LS_STOPPED:
00625       fsm_sdata(f, TERMACK, (u_char)id, NULL, 0);
00626       break;
00627     
00628     case LS_REQSENT:
00629     case LS_ACKSENT:
00630       /* They didn't agree to what we wanted - try another request */
00631       UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */
00632       if (ret < 0) {
00633         f->state = LS_STOPPED;    /* kludge for stopping CCP */
00634       } else {
00635         fsm_sconfreq(f, 0);    /* Send Configure-Request */
00636       }
00637       break;
00638     
00639     case LS_ACKRCVD:
00640       /* Got a Nak/reject when we had already had an Ack?? oh well... */
00641       UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */
00642       fsm_sconfreq(f, 0);
00643       f->state = LS_REQSENT;
00644       break;
00645     
00646     case LS_OPENED:
00647       /* Go down and restart negotiation */
00648       if (f->callbacks->down) {
00649         (*f->callbacks->down)(f);  /* Inform upper layers */
00650       }
00651       fsm_sconfreq(f, 0);    /* Send initial Configure-Request */
00652       f->state = LS_REQSENT;
00653       break;
00654   }
00655 }
00656 
00657 
00658 /*
00659  * fsm_rtermreq - Receive Terminate-Req.
00660  */
00661 static void
00662 fsm_rtermreq(fsm *f, int id, u_char *p, int len)
00663 {
00664   LWIP_UNUSED_ARG(p);
00665 
00666   FSMDEBUG(LOG_INFO, ("fsm_rtermreq(%s): Rcvd id %d state=%d (%s)\n",
00667         PROTO_NAME(f), id, f->state, ppperr_strerr[f->state]));
00668 
00669   switch (f->state) {
00670     case LS_ACKRCVD:
00671     case LS_ACKSENT:
00672       f->state = LS_REQSENT;    /* Start over but keep trying */
00673       break;
00674 
00675     case LS_OPENED:
00676       if (len > 0) {
00677         FSMDEBUG(LOG_INFO, ("%s terminated by peer (%p)\n", PROTO_NAME(f), p));
00678       } else {
00679         FSMDEBUG(LOG_INFO, ("%s terminated by peer\n", PROTO_NAME(f)));
00680       }
00681       if (f->callbacks->down) {
00682         (*f->callbacks->down)(f);  /* Inform upper layers */
00683       }
00684       f->retransmits = 0;
00685       f->state = LS_STOPPING;
00686       TIMEOUT(fsm_timeout, f, f->timeouttime);
00687       break;
00688   }
00689 
00690   fsm_sdata(f, TERMACK, (u_char)id, NULL, 0);
00691 }
00692 
00693 
00694 /*
00695  * fsm_rtermack - Receive Terminate-Ack.
00696  */
00697 static void
00698 fsm_rtermack(fsm *f)
00699 {
00700   FSMDEBUG(LOG_INFO, ("fsm_rtermack(%s): state=%d (%s)\n", 
00701         PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
00702   
00703   switch (f->state) {
00704     case LS_CLOSING:
00705       UNTIMEOUT(fsm_timeout, f);
00706       f->state = LS_CLOSED;
00707       if( f->callbacks->finished ) {
00708         (*f->callbacks->finished)(f);
00709       }
00710       break;
00711 
00712     case LS_STOPPING:
00713       UNTIMEOUT(fsm_timeout, f);
00714       f->state = LS_STOPPED;
00715       if( f->callbacks->finished ) {
00716         (*f->callbacks->finished)(f);
00717       }
00718       break;
00719     
00720     case LS_ACKRCVD:
00721       f->state = LS_REQSENT;
00722       break;
00723     
00724     case LS_OPENED:
00725       if (f->callbacks->down) {
00726         (*f->callbacks->down)(f);  /* Inform upper layers */
00727       }
00728       fsm_sconfreq(f, 0);
00729       break;
00730     default:
00731       FSMDEBUG(LOG_INFO, ("fsm_rtermack(%s): UNHANDLED state=%d (%s)!!!\n", 
00732                 PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
00733   }
00734 }
00735 
00736 
00737 /*
00738  * fsm_rcoderej - Receive an Code-Reject.
00739  */
00740 static void
00741 fsm_rcoderej(fsm *f, u_char *inp, int len)
00742 {
00743   u_char code, id;
00744   
00745   FSMDEBUG(LOG_INFO, ("fsm_rcoderej(%s): state=%d (%s)\n", 
00746         PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
00747   
00748   if (len < HEADERLEN) {
00749     FSMDEBUG(LOG_INFO, ("fsm_rcoderej: Rcvd short Code-Reject packet!\n"));
00750     return;
00751   }
00752   GETCHAR(code, inp);
00753   GETCHAR(id, inp);
00754   FSMDEBUG(LOG_WARNING, ("%s: Rcvd Code-Reject for code %d, id %d\n",
00755         PROTO_NAME(f), code, id));
00756   
00757   if( f->state == LS_ACKRCVD ) {
00758     f->state = LS_REQSENT;
00759   }
00760 }
00761 
00762 
00763 /*
00764  * fsm_protreject - Peer doesn't speak this protocol.
00765  *
00766  * Treat this as a catastrophic error (RXJ-).
00767  */
00768 void
00769 fsm_protreject(fsm *f)
00770 {
00771   switch( f->state ) {
00772     case LS_CLOSING:
00773       UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */
00774       /* fall through */
00775     case LS_CLOSED:
00776       f->state = LS_CLOSED;
00777       if( f->callbacks->finished ) {
00778         (*f->callbacks->finished)(f);
00779       }
00780       break;
00781 
00782     case LS_STOPPING:
00783     case LS_REQSENT:
00784     case LS_ACKRCVD:
00785     case LS_ACKSENT:
00786       UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */
00787       /* fall through */
00788     case LS_STOPPED:
00789       f->state = LS_STOPPED;
00790       if( f->callbacks->finished ) {
00791         (*f->callbacks->finished)(f);
00792       }
00793       break;
00794     
00795     case LS_OPENED:
00796       if( f->callbacks->down ) {
00797         (*f->callbacks->down)(f);
00798       }
00799       /* Init restart counter, send Terminate-Request */
00800       f->retransmits = f->maxtermtransmits;
00801       fsm_sdata(f, TERMREQ, f->reqid = ++f->id,
00802             (u_char *) f->term_reason, f->term_reason_len);
00803       TIMEOUT(fsm_timeout, f, f->timeouttime);
00804       --f->retransmits;
00805 
00806       f->state = LS_STOPPING;
00807       break;
00808     
00809     default:
00810       FSMDEBUG(LOG_INFO, ("%s: Protocol-reject event in state %d (%s)!\n",
00811             PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
00812     }
00813 }
00814 
00815 
00816 /*
00817  * fsm_sconfreq - Send a Configure-Request.
00818  */
00819 static void
00820 fsm_sconfreq(fsm *f, int retransmit)
00821 {
00822   u_char *outp;
00823   int cilen;
00824   
00825   if( f->state != LS_REQSENT && f->state != LS_ACKRCVD && f->state != LS_ACKSENT ) {
00826     /* Not currently negotiating - reset options */
00827     if( f->callbacks->resetci ) {
00828       (*f->callbacks->resetci)(f);
00829     }
00830     f->nakloops = 0;
00831   }
00832   
00833   if( !retransmit ) {
00834     /* New request - reset retransmission counter, use new ID */
00835     f->retransmits = f->maxconfreqtransmits;
00836     f->reqid = ++f->id;
00837   }
00838   
00839   f->seen_ack = 0;
00840   
00841   /*
00842    * Make up the request packet
00843    */
00844   outp = outpacket_buf[f->unit] + PPP_HDRLEN + HEADERLEN;
00845   if( f->callbacks->cilen && f->callbacks->addci ) {
00846     cilen = (*f->callbacks->cilen)(f);
00847     if( cilen > peer_mru[f->unit] - (int)HEADERLEN ) {
00848       cilen = peer_mru[f->unit] - HEADERLEN;
00849     }
00850     if (f->callbacks->addci) {
00851       (*f->callbacks->addci)(f, outp, &cilen);
00852     }
00853   } else {
00854     cilen = 0;
00855   }
00856 
00857   /* send the request to our peer */
00858   fsm_sdata(f, CONFREQ, f->reqid, outp, cilen);
00859   
00860   /* start the retransmit timer */
00861   --f->retransmits;
00862   TIMEOUT(fsm_timeout, f, f->timeouttime);
00863   
00864   FSMDEBUG(LOG_INFO, ("%s: sending Configure-Request, id %d\n",
00865         PROTO_NAME(f), f->reqid));
00866 }
00867 
00868 
00869 /*
00870  * fsm_sdata - Send some data.
00871  *
00872  * Used for all packets sent to our peer by this module.
00873  */
00874 void
00875 fsm_sdata( fsm *f, u_char code, u_char id, u_char *data, int datalen)
00876 {
00877   u_char *outp;
00878   int outlen;
00879 
00880   /* Adjust length to be smaller than MTU */
00881   outp = outpacket_buf[f->unit];
00882   if (datalen > peer_mru[f->unit] - (int)HEADERLEN) {
00883     datalen = peer_mru[f->unit] - HEADERLEN;
00884   }
00885   if (datalen && data != outp + PPP_HDRLEN + HEADERLEN) {
00886     BCOPY(data, outp + PPP_HDRLEN + HEADERLEN, datalen);
00887   }
00888   outlen = datalen + HEADERLEN;
00889   MAKEHEADER(outp, f->protocol);
00890   PUTCHAR(code, outp);
00891   PUTCHAR(id, outp);
00892   PUTSHORT(outlen, outp);
00893   pppWrite(f->unit, outpacket_buf[f->unit], outlen + PPP_HDRLEN);
00894   FSMDEBUG(LOG_INFO, ("fsm_sdata(%s): Sent code %d,%d,%d.\n",
00895         PROTO_NAME(f), code, id, outlen));
00896 }
00897 
00898 #endif /* PPP_SUPPORT */