Control a robot over the internet using UDP and a Ethernet interface.

Dependencies:   EthernetInterface Motor TextLCD mbed-rtos mbed Socket lwip-eth lwip-sys lwip

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   int oldState = f->state;
00124 
00125   LWIP_UNUSED_ARG(oldState);
00126 
00127   switch( f->state ) {
00128     case LS_INITIAL:
00129       f->state = LS_CLOSED;
00130       break;
00131 
00132     case LS_STARTING:
00133       if( f->flags & OPT_SILENT ) {
00134         f->state = LS_STOPPED;
00135       } else {
00136         /* Send an initial configure-request */
00137         fsm_sconfreq(f, 0);
00138         f->state = LS_REQSENT;
00139       }
00140     break;
00141 
00142     default:
00143       FSMDEBUG(LOG_INFO, ("%s: Up event in state %d (%s)!\n",
00144           PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
00145   }
00146 
00147   FSMDEBUG(LOG_INFO, ("%s: lowerup state %d (%s) -> %d (%s)\n",
00148       PROTO_NAME(f), oldState, ppperr_strerr[oldState], f->state, ppperr_strerr[f->state]));
00149 }
00150 
00151 
00152 /*
00153  * fsm_lowerdown - The lower layer is down.
00154  *
00155  * Cancel all timeouts and inform upper layers.
00156  */
00157 void
00158 fsm_lowerdown(fsm *f)
00159 {
00160   int oldState = f->state;
00161 
00162   LWIP_UNUSED_ARG(oldState);
00163 
00164   switch( f->state ) {
00165     case LS_CLOSED:
00166       f->state = LS_INITIAL;
00167       break;
00168 
00169     case LS_STOPPED:
00170       f->state = LS_STARTING;
00171       if( f->callbacks->starting ) {
00172         (*f->callbacks->starting)(f);
00173       }
00174       break;
00175 
00176     case LS_CLOSING:
00177       f->state = LS_INITIAL;
00178       UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */
00179       break;
00180 
00181     case LS_STOPPING:
00182     case LS_REQSENT:
00183     case LS_ACKRCVD:
00184     case LS_ACKSENT:
00185       f->state = LS_STARTING;
00186       UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */
00187       break;
00188 
00189     case LS_OPENED:
00190       if( f->callbacks->down ) {
00191         (*f->callbacks->down)(f);
00192       }
00193       f->state = LS_STARTING;
00194       break;
00195 
00196     default:
00197       FSMDEBUG(LOG_INFO, ("%s: Down event in state %d (%s)!\n",
00198           PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
00199   }
00200 
00201   FSMDEBUG(LOG_INFO, ("%s: lowerdown state %d (%s) -> %d (%s)\n",
00202       PROTO_NAME(f), oldState, ppperr_strerr[oldState], f->state, ppperr_strerr[f->state]));
00203 }
00204 
00205 
00206 /*
00207  * fsm_open - Link is allowed to come up.
00208  */
00209 void
00210 fsm_open(fsm *f)
00211 {
00212   int oldState = f->state;
00213 
00214   LWIP_UNUSED_ARG(oldState);
00215 
00216   switch( f->state ) {
00217     case LS_INITIAL:
00218       f->state = LS_STARTING;
00219       if( f->callbacks->starting ) {
00220         (*f->callbacks->starting)(f);
00221       }
00222       break;
00223 
00224     case LS_CLOSED:
00225       if( f->flags & OPT_SILENT ) {
00226         f->state = LS_STOPPED;
00227       } else {
00228         /* Send an initial configure-request */
00229         fsm_sconfreq(f, 0);
00230         f->state = LS_REQSENT;
00231       }
00232       break;
00233   
00234     case LS_CLOSING:
00235       f->state = LS_STOPPING;
00236       /* fall through */
00237     case LS_STOPPED:
00238     case LS_OPENED:
00239       if( f->flags & OPT_RESTART ) {
00240         fsm_lowerdown(f);
00241         fsm_lowerup(f);
00242       }
00243       break;
00244   }
00245 
00246   FSMDEBUG(LOG_INFO, ("%s: open state %d (%s) -> %d (%s)\n",
00247       PROTO_NAME(f), oldState, ppperr_strerr[oldState], f->state, ppperr_strerr[f->state]));
00248 }
00249 
00250 #if 0 /* backport pppd 2.4.4b1; */
00251 /*
00252  * terminate_layer - Start process of shutting down the FSM
00253  *
00254  * Cancel any timeout running, notify upper layers we're done, and
00255  * send a terminate-request message as configured.
00256  */
00257 static void
00258 terminate_layer(fsm *f, int nextstate)
00259 {
00260   /* @todo */
00261 }
00262 #endif
00263 
00264 /*
00265  * fsm_close - Start closing connection.
00266  *
00267  * Cancel timeouts and either initiate close or possibly go directly to
00268  * the LS_CLOSED state.
00269  */
00270 void
00271 fsm_close(fsm *f, char *reason)
00272 {
00273   int oldState = f->state;
00274 
00275   LWIP_UNUSED_ARG(oldState);
00276 
00277   f->term_reason = reason;
00278   f->term_reason_len = (reason == NULL ? 0 : (int)strlen(reason));
00279   switch( f->state ) {
00280     case LS_STARTING:
00281       f->state = LS_INITIAL;
00282       break;
00283     case LS_STOPPED:
00284       f->state = LS_CLOSED;
00285       break;
00286     case LS_STOPPING:
00287       f->state = LS_CLOSING;
00288       break;
00289 
00290     case LS_REQSENT:
00291     case LS_ACKRCVD:
00292     case LS_ACKSENT:
00293     case LS_OPENED:
00294       if( f->state != LS_OPENED ) {
00295         UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */
00296       } else if( f->callbacks->down ) {
00297         (*f->callbacks->down)(f);  /* Inform upper layers we're down */
00298       }
00299       /* Init restart counter, send Terminate-Request */
00300       f->retransmits = f->maxtermtransmits;
00301       fsm_sdata(f, TERMREQ, f->reqid = ++f->id,
00302             (u_char *) f->term_reason, f->term_reason_len);
00303       TIMEOUT(fsm_timeout, f, f->timeouttime);
00304       --f->retransmits;
00305 
00306       f->state = LS_CLOSING;
00307       break;
00308   }
00309 
00310   FSMDEBUG(LOG_INFO, ("%s: close reason=%s state %d (%s) -> %d (%s)\n",
00311       PROTO_NAME(f), reason, oldState, ppperr_strerr[oldState], f->state, ppperr_strerr[f->state]));
00312 }
00313 
00314 
00315 /*
00316  * fsm_timeout - Timeout expired.
00317  */
00318 static void
00319 fsm_timeout(void *arg)
00320 {
00321   fsm *f = (fsm *) arg;
00322 
00323   switch (f->state) {
00324     case LS_CLOSING:
00325     case LS_STOPPING:
00326       if( f->retransmits <= 0 ) {
00327         FSMDEBUG(LOG_WARNING, ("%s: timeout sending Terminate-Request state=%d (%s)\n",
00328              PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
00329         /*
00330          * We've waited for an ack long enough.  Peer probably heard us.
00331          */
00332         f->state = (f->state == LS_CLOSING)? LS_CLOSED: LS_STOPPED;
00333         if( f->callbacks->finished ) {
00334           (*f->callbacks->finished)(f);
00335         }
00336       } else {
00337         FSMDEBUG(LOG_WARNING, ("%s: timeout resending Terminate-Requests state=%d (%s)\n",
00338              PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
00339         /* Send Terminate-Request */
00340         fsm_sdata(f, TERMREQ, f->reqid = ++f->id,
00341             (u_char *) f->term_reason, f->term_reason_len);
00342         TIMEOUT(fsm_timeout, f, f->timeouttime);
00343         --f->retransmits;
00344       }
00345       break;
00346 
00347     case LS_REQSENT:
00348     case LS_ACKRCVD:
00349     case LS_ACKSENT:
00350       if (f->retransmits <= 0) {
00351         FSMDEBUG(LOG_WARNING, ("%s: timeout sending Config-Requests state=%d (%s)\n",
00352          PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
00353         f->state = LS_STOPPED;
00354         if( (f->flags & OPT_PASSIVE) == 0 && f->callbacks->finished ) {
00355           (*f->callbacks->finished)(f);
00356         }
00357       } else {
00358         FSMDEBUG(LOG_WARNING, ("%s: timeout resending Config-Request state=%d (%s)\n",
00359          PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
00360         /* Retransmit the configure-request */
00361         if (f->callbacks->retransmit) {
00362           (*f->callbacks->retransmit)(f);
00363         }
00364         fsm_sconfreq(f, 1);    /* Re-send Configure-Request */
00365         if( f->state == LS_ACKRCVD ) {
00366           f->state = LS_REQSENT;
00367         }
00368       }
00369       break;
00370 
00371     default:
00372       FSMDEBUG(LOG_INFO, ("%s: UNHANDLED timeout event in state %d (%s)!\n",
00373           PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
00374   }
00375 }
00376 
00377 
00378 /*
00379  * fsm_input - Input packet.
00380  */
00381 void
00382 fsm_input(fsm *f, u_char *inpacket, int l)
00383 {
00384   u_char *inp = inpacket;
00385   u_char code, id;
00386   int len;
00387 
00388   /*
00389   * Parse header (code, id and length).
00390   * If packet too short, drop it.
00391   */
00392   if (l < HEADERLEN) {
00393     FSMDEBUG(LOG_WARNING, ("fsm_input(%x): Rcvd short header.\n",
00394           f->protocol));
00395     return;
00396   }
00397   GETCHAR(code, inp);
00398   GETCHAR(id, inp);
00399   GETSHORT(len, inp);
00400   if (len < HEADERLEN) {
00401     FSMDEBUG(LOG_INFO, ("fsm_input(%x): Rcvd illegal length.\n",
00402         f->protocol));
00403     return;
00404   }
00405   if (len > l) {
00406     FSMDEBUG(LOG_INFO, ("fsm_input(%x): Rcvd short packet.\n",
00407         f->protocol));
00408     return;
00409   }
00410   len -= HEADERLEN;    /* subtract header length */
00411 
00412   if( f->state == LS_INITIAL || f->state == LS_STARTING ) {
00413     FSMDEBUG(LOG_INFO, ("fsm_input(%x): Rcvd packet in state %d (%s).\n",
00414         f->protocol, f->state, ppperr_strerr[f->state]));
00415     return;
00416   }
00417   FSMDEBUG(LOG_INFO, ("fsm_input(%s):%d,%d,%d\n", PROTO_NAME(f), code, id, l));
00418   /*
00419    * Action depends on code.
00420    */
00421   switch (code) {
00422     case CONFREQ:
00423       fsm_rconfreq(f, id, inp, len);
00424       break;
00425     
00426     case CONFACK:
00427       fsm_rconfack(f, id, inp, len);
00428       break;
00429     
00430     case CONFNAK:
00431     case CONFREJ:
00432       fsm_rconfnakrej(f, code, id, inp, len);
00433       break;
00434     
00435     case TERMREQ:
00436       fsm_rtermreq(f, id, inp, len);
00437       break;
00438     
00439     case TERMACK:
00440       fsm_rtermack(f);
00441       break;
00442     
00443     case CODEREJ:
00444       fsm_rcoderej(f, inp, len);
00445       break;
00446     
00447     default:
00448       FSMDEBUG(LOG_INFO, ("fsm_input(%s): default: \n", PROTO_NAME(f)));
00449       if( !f->callbacks->extcode ||
00450           !(*f->callbacks->extcode)(f, code, id, inp, len) ) {
00451         fsm_sdata(f, CODEREJ, ++f->id, inpacket, len + HEADERLEN);
00452       }
00453       break;
00454   }
00455 }
00456 
00457 
00458 /*
00459  * fsm_rconfreq - Receive Configure-Request.
00460  */
00461 static void
00462 fsm_rconfreq(fsm *f, u_char id, u_char *inp, int len)
00463 {
00464   int code, reject_if_disagree;
00465 
00466   FSMDEBUG(LOG_INFO, ("fsm_rconfreq(%s): Rcvd id %d state=%d (%s)\n", 
00467         PROTO_NAME(f), id, f->state, ppperr_strerr[f->state]));
00468   switch( f->state ) {
00469     case LS_CLOSED:
00470       /* Go away, we're closed */
00471       fsm_sdata(f, TERMACK, id, NULL, 0);
00472       return;
00473     case LS_CLOSING:
00474     case LS_STOPPING:
00475       return;
00476 
00477     case LS_OPENED:
00478       /* Go down and restart negotiation */
00479       if( f->callbacks->down ) {
00480         (*f->callbacks->down)(f);  /* Inform upper layers */
00481       }
00482       fsm_sconfreq(f, 0);    /* Send initial Configure-Request */
00483       break;
00484 
00485     case LS_STOPPED:
00486       /* Negotiation started by our peer */
00487       fsm_sconfreq(f, 0);    /* Send initial Configure-Request */
00488       f->state = LS_REQSENT;
00489       break;
00490   }
00491   
00492   /*
00493   * Pass the requested configuration options
00494   * to protocol-specific code for checking.
00495   */
00496   if (f->callbacks->reqci) {    /* Check CI */
00497     reject_if_disagree = (f->nakloops >= f->maxnakloops);
00498     code = (*f->callbacks->reqci)(f, inp, &len, reject_if_disagree);
00499   } else if (len) {
00500     code = CONFREJ;      /* Reject all CI */
00501   } else {
00502     code = CONFACK;
00503   }
00504   
00505   /* send the Ack, Nak or Rej to the peer */
00506   fsm_sdata(f, (u_char)code, id, inp, len);
00507   
00508   if (code == CONFACK) {
00509     if (f->state == LS_ACKRCVD) {
00510       UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */
00511       f->state = LS_OPENED;
00512       if (f->callbacks->up) {
00513         (*f->callbacks->up)(f);  /* Inform upper layers */
00514       }
00515     } else {
00516       f->state = LS_ACKSENT;
00517     }
00518     f->nakloops = 0;
00519   } else {
00520     /* we sent CONFACK or CONFREJ */
00521     if (f->state != LS_ACKRCVD) {
00522       f->state = LS_REQSENT;
00523     }
00524     if( code == CONFNAK ) {
00525       ++f->nakloops;
00526     }
00527   }
00528 }
00529 
00530 
00531 /*
00532  * fsm_rconfack - Receive Configure-Ack.
00533  */
00534 static void
00535 fsm_rconfack(fsm *f, int id, u_char *inp, int len)
00536 {
00537   FSMDEBUG(LOG_INFO, ("fsm_rconfack(%s): Rcvd id %d state=%d (%s)\n",
00538         PROTO_NAME(f), id, f->state, ppperr_strerr[f->state]));
00539   
00540   if (id != f->reqid || f->seen_ack) {   /* Expected id? */
00541     return; /* Nope, toss... */
00542   }
00543   if( !(f->callbacks->ackci? (*f->callbacks->ackci)(f, inp, len): (len == 0)) ) {
00544     /* Ack is bad - ignore it */
00545     FSMDEBUG(LOG_INFO, ("%s: received bad Ack (length %d)\n",
00546           PROTO_NAME(f), len));
00547     return;
00548   }
00549   f->seen_ack = 1;
00550   
00551   switch (f->state) {
00552     case LS_CLOSED:
00553     case LS_STOPPED:
00554       fsm_sdata(f, TERMACK, (u_char)id, NULL, 0);
00555       break;
00556     
00557     case LS_REQSENT:
00558       f->state = LS_ACKRCVD;
00559       f->retransmits = f->maxconfreqtransmits;
00560       break;
00561     
00562     case LS_ACKRCVD:
00563       /* Huh? an extra valid Ack? oh well... */
00564       UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */
00565       fsm_sconfreq(f, 0);
00566       f->state = LS_REQSENT;
00567       break;
00568     
00569     case LS_ACKSENT:
00570       UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */
00571       f->state = LS_OPENED;
00572       f->retransmits = f->maxconfreqtransmits;
00573       if (f->callbacks->up) {
00574         (*f->callbacks->up)(f);  /* Inform upper layers */
00575       }
00576       break;
00577     
00578     case LS_OPENED:
00579       /* Go down and restart negotiation */
00580       if (f->callbacks->down) {
00581         (*f->callbacks->down)(f);  /* Inform upper layers */
00582       }
00583       fsm_sconfreq(f, 0);    /* Send initial Configure-Request */
00584       f->state = LS_REQSENT;
00585       break;
00586   }
00587 }
00588 
00589 
00590 /*
00591  * fsm_rconfnakrej - Receive Configure-Nak or Configure-Reject.
00592  */
00593 static void
00594 fsm_rconfnakrej(fsm *f, int code, int id, u_char *inp, int len)
00595 {
00596   int (*proc) (fsm *, u_char *, int);
00597   int ret;
00598 
00599   FSMDEBUG(LOG_INFO, ("fsm_rconfnakrej(%s): Rcvd id %d state=%d (%s)\n",
00600         PROTO_NAME(f), id, f->state, ppperr_strerr[f->state]));
00601 
00602   if (id != f->reqid || f->seen_ack) { /* Expected id? */
00603     return;        /* Nope, toss... */
00604   }
00605   proc = (code == CONFNAK)? f->callbacks->nakci: f->callbacks->rejci;
00606   if (!proc || !((ret = proc(f, inp, len)))) {
00607     /* Nak/reject is bad - ignore it */
00608     FSMDEBUG(LOG_INFO, ("%s: received bad %s (length %d)\n",
00609           PROTO_NAME(f), (code==CONFNAK? "Nak": "reject"), len));
00610     return;
00611   }
00612   f->seen_ack = 1;
00613 
00614   switch (f->state) {
00615     case LS_CLOSED:
00616     case LS_STOPPED:
00617       fsm_sdata(f, TERMACK, (u_char)id, NULL, 0);
00618       break;
00619     
00620     case LS_REQSENT:
00621     case LS_ACKSENT:
00622       /* They didn't agree to what we wanted - try another request */
00623       UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */
00624       if (ret < 0) {
00625         f->state = LS_STOPPED;    /* kludge for stopping CCP */
00626       } else {
00627         fsm_sconfreq(f, 0);    /* Send Configure-Request */
00628       }
00629       break;
00630     
00631     case LS_ACKRCVD:
00632       /* Got a Nak/reject when we had already had an Ack?? oh well... */
00633       UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */
00634       fsm_sconfreq(f, 0);
00635       f->state = LS_REQSENT;
00636       break;
00637     
00638     case LS_OPENED:
00639       /* Go down and restart negotiation */
00640       if (f->callbacks->down) {
00641         (*f->callbacks->down)(f);  /* Inform upper layers */
00642       }
00643       fsm_sconfreq(f, 0);    /* Send initial Configure-Request */
00644       f->state = LS_REQSENT;
00645       break;
00646   }
00647 }
00648 
00649 
00650 /*
00651  * fsm_rtermreq - Receive Terminate-Req.
00652  */
00653 static void
00654 fsm_rtermreq(fsm *f, int id, u_char *p, int len)
00655 {
00656   LWIP_UNUSED_ARG(p);
00657 
00658   FSMDEBUG(LOG_INFO, ("fsm_rtermreq(%s): Rcvd id %d state=%d (%s)\n",
00659         PROTO_NAME(f), id, f->state, ppperr_strerr[f->state]));
00660 
00661   switch (f->state) {
00662     case LS_ACKRCVD:
00663     case LS_ACKSENT:
00664       f->state = LS_REQSENT;    /* Start over but keep trying */
00665       break;
00666 
00667     case LS_OPENED:
00668       if (len > 0) {
00669         FSMDEBUG(LOG_INFO, ("%s terminated by peer (%p)\n", PROTO_NAME(f), p));
00670       } else {
00671         FSMDEBUG(LOG_INFO, ("%s terminated by peer\n", PROTO_NAME(f)));
00672       }
00673       if (f->callbacks->down) {
00674         (*f->callbacks->down)(f);  /* Inform upper layers */
00675       }
00676       f->retransmits = 0;
00677       f->state = LS_STOPPING;
00678       TIMEOUT(fsm_timeout, f, f->timeouttime);
00679       break;
00680   }
00681 
00682   fsm_sdata(f, TERMACK, (u_char)id, NULL, 0);
00683 }
00684 
00685 
00686 /*
00687  * fsm_rtermack - Receive Terminate-Ack.
00688  */
00689 static void
00690 fsm_rtermack(fsm *f)
00691 {
00692   FSMDEBUG(LOG_INFO, ("fsm_rtermack(%s): state=%d (%s)\n", 
00693         PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
00694   
00695   switch (f->state) {
00696     case LS_CLOSING:
00697       UNTIMEOUT(fsm_timeout, f);
00698       f->state = LS_CLOSED;
00699       if( f->callbacks->finished ) {
00700         (*f->callbacks->finished)(f);
00701       }
00702       break;
00703 
00704     case LS_STOPPING:
00705       UNTIMEOUT(fsm_timeout, f);
00706       f->state = LS_STOPPED;
00707       if( f->callbacks->finished ) {
00708         (*f->callbacks->finished)(f);
00709       }
00710       break;
00711     
00712     case LS_ACKRCVD:
00713       f->state = LS_REQSENT;
00714       break;
00715     
00716     case LS_OPENED:
00717       if (f->callbacks->down) {
00718         (*f->callbacks->down)(f);  /* Inform upper layers */
00719       }
00720       fsm_sconfreq(f, 0);
00721       break;
00722     default:
00723       FSMDEBUG(LOG_INFO, ("fsm_rtermack(%s): UNHANDLED state=%d (%s)!!!\n", 
00724                 PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
00725   }
00726 }
00727 
00728 
00729 /*
00730  * fsm_rcoderej - Receive an Code-Reject.
00731  */
00732 static void
00733 fsm_rcoderej(fsm *f, u_char *inp, int len)
00734 {
00735   u_char code, id;
00736   
00737   FSMDEBUG(LOG_INFO, ("fsm_rcoderej(%s): state=%d (%s)\n", 
00738         PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
00739   
00740   if (len < HEADERLEN) {
00741     FSMDEBUG(LOG_INFO, ("fsm_rcoderej: Rcvd short Code-Reject packet!\n"));
00742     return;
00743   }
00744   GETCHAR(code, inp);
00745   GETCHAR(id, inp);
00746   FSMDEBUG(LOG_WARNING, ("%s: Rcvd Code-Reject for code %d, id %d\n",
00747         PROTO_NAME(f), code, id));
00748   
00749   if( f->state == LS_ACKRCVD ) {
00750     f->state = LS_REQSENT;
00751   }
00752 }
00753 
00754 
00755 /*
00756  * fsm_protreject - Peer doesn't speak this protocol.
00757  *
00758  * Treat this as a catastrophic error (RXJ-).
00759  */
00760 void
00761 fsm_protreject(fsm *f)
00762 {
00763   switch( f->state ) {
00764     case LS_CLOSING:
00765       UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */
00766       /* fall through */
00767     case LS_CLOSED:
00768       f->state = LS_CLOSED;
00769       if( f->callbacks->finished ) {
00770         (*f->callbacks->finished)(f);
00771       }
00772       break;
00773 
00774     case LS_STOPPING:
00775     case LS_REQSENT:
00776     case LS_ACKRCVD:
00777     case LS_ACKSENT:
00778       UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */
00779       /* fall through */
00780     case LS_STOPPED:
00781       f->state = LS_STOPPED;
00782       if( f->callbacks->finished ) {
00783         (*f->callbacks->finished)(f);
00784       }
00785       break;
00786     
00787     case LS_OPENED:
00788       if( f->callbacks->down ) {
00789         (*f->callbacks->down)(f);
00790       }
00791       /* Init restart counter, send Terminate-Request */
00792       f->retransmits = f->maxtermtransmits;
00793       fsm_sdata(f, TERMREQ, f->reqid = ++f->id,
00794             (u_char *) f->term_reason, f->term_reason_len);
00795       TIMEOUT(fsm_timeout, f, f->timeouttime);
00796       --f->retransmits;
00797 
00798       f->state = LS_STOPPING;
00799       break;
00800     
00801     default:
00802       FSMDEBUG(LOG_INFO, ("%s: Protocol-reject event in state %d (%s)!\n",
00803             PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
00804     }
00805 }
00806 
00807 
00808 /*
00809  * fsm_sconfreq - Send a Configure-Request.
00810  */
00811 static void
00812 fsm_sconfreq(fsm *f, int retransmit)
00813 {
00814   u_char *outp;
00815   int cilen;
00816   
00817   if( f->state != LS_REQSENT && f->state != LS_ACKRCVD && f->state != LS_ACKSENT ) {
00818     /* Not currently negotiating - reset options */
00819     if( f->callbacks->resetci ) {
00820       (*f->callbacks->resetci)(f);
00821     }
00822     f->nakloops = 0;
00823   }
00824   
00825   if( !retransmit ) {
00826     /* New request - reset retransmission counter, use new ID */
00827     f->retransmits = f->maxconfreqtransmits;
00828     f->reqid = ++f->id;
00829   }
00830   
00831   f->seen_ack = 0;
00832   
00833   /*
00834    * Make up the request packet
00835    */
00836   outp = outpacket_buf[f->unit] + PPP_HDRLEN + HEADERLEN;
00837   if( f->callbacks->cilen && f->callbacks->addci ) {
00838     cilen = (*f->callbacks->cilen)(f);
00839     if( cilen > peer_mru[f->unit] - (int)HEADERLEN ) {
00840       cilen = peer_mru[f->unit] - HEADERLEN;
00841     }
00842     if (f->callbacks->addci) {
00843       (*f->callbacks->addci)(f, outp, &cilen);
00844     }
00845   } else {
00846     cilen = 0;
00847   }
00848 
00849   /* send the request to our peer */
00850   fsm_sdata(f, CONFREQ, f->reqid, outp, cilen);
00851   
00852   /* start the retransmit timer */
00853   --f->retransmits;
00854   TIMEOUT(fsm_timeout, f, f->timeouttime);
00855   
00856   FSMDEBUG(LOG_INFO, ("%s: sending Configure-Request, id %d\n",
00857         PROTO_NAME(f), f->reqid));
00858 }
00859 
00860 
00861 /*
00862  * fsm_sdata - Send some data.
00863  *
00864  * Used for all packets sent to our peer by this module.
00865  */
00866 void
00867 fsm_sdata( fsm *f, u_char code, u_char id, u_char *data, int datalen)
00868 {
00869   u_char *outp;
00870   int outlen;
00871 
00872   /* Adjust length to be smaller than MTU */
00873   outp = outpacket_buf[f->unit];
00874   if (datalen > peer_mru[f->unit] - (int)HEADERLEN) {
00875     datalen = peer_mru[f->unit] - HEADERLEN;
00876   }
00877   if (datalen && data != outp + PPP_HDRLEN + HEADERLEN) {
00878     BCOPY(data, outp + PPP_HDRLEN + HEADERLEN, datalen);
00879   }
00880   outlen = datalen + HEADERLEN;
00881   MAKEHEADER(outp, f->protocol);
00882   PUTCHAR(code, outp);
00883   PUTCHAR(id, outp);
00884   PUTSHORT(outlen, outp);
00885   pppWrite(f->unit, outpacket_buf[f->unit], outlen + PPP_HDRLEN);
00886   FSMDEBUG(LOG_INFO, ("fsm_sdata(%s): Sent code %d,%d,%d.\n",
00887         PROTO_NAME(f), code, id, outlen));
00888 }
00889 
00890 #endif /* PPP_SUPPORT */