SAMV71 Xplained Ultra Software Package 1.3

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