Example program with HTTPServer and sensor data streaming over TCPSockets, using Donatien Garnier's Net APIs and services code on top of LWIP. Files StreamServer.h and .cpp encapsulate streaming over TCPSockets. Broadcast is done by sendToAll(), and all incoming data is echoed back to the client. Echo code can be replaced with some remote control of the streaming interface. See main() that shows how to periodically send some data to all subscribed clients. To subscribe, a client should open a socket at <mbed_ip> port 123. I used few lines in TCL code to set up a quick sink for the data. HTTP files are served on port 80 concurrently to the streaming.

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 */