Rtos API example

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers lwip_fsm.c Source File

lwip_fsm.c

00001 /*
00002  * fsm.c - {Link, IP} Control Protocol Finite State Machine.
00003  *
00004  * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved.
00005  *
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions
00008  * are met:
00009  *
00010  * 1. Redistributions of source code must retain the above copyright
00011  *    notice, this list of conditions and the following disclaimer.
00012  *
00013  * 2. Redistributions in binary form must reproduce the above copyright
00014  *    notice, this list of conditions and the following disclaimer in
00015  *    the documentation and/or other materials provided with the
00016  *    distribution.
00017  *
00018  * 3. The name "Carnegie Mellon University" must not be used to
00019  *    endorse or promote products derived from this software without
00020  *    prior written permission. For permission or any legal
00021  *    details, please contact
00022  *      Office of Technology Transfer
00023  *      Carnegie Mellon University
00024  *      5000 Forbes Avenue
00025  *      Pittsburgh, PA  15213-3890
00026  *      (412) 268-4387, fax: (412) 268-7395
00027  *      tech-transfer@andrew.cmu.edu
00028  *
00029  * 4. Redistributions of any form whatsoever must retain the following
00030  *    acknowledgment:
00031  *    "This product includes software developed by Computing Services
00032  *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
00033  *
00034  * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
00035  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00036  * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
00037  * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
00038  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
00039  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
00040  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
00041  */
00042 
00043 #include "netif/ppp/ppp_opts.h"
00044 #if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */
00045 
00046 /*
00047  * @todo:
00048  * Randomize fsm id on link/init.
00049  * Deal with variable outgoing MTU.
00050  */
00051 
00052 #if 0 /* UNUSED */
00053 #include <stdio.h>
00054 #include <string.h>
00055 #include <sys/types.h>
00056 #endif /* UNUSED */
00057 
00058 #include "netif/ppp/ppp_impl.h"
00059 
00060 #include "netif/ppp/fsm.h"
00061 
00062 static void fsm_timeout (void *);
00063 static void fsm_rconfreq(fsm *f, u_char id, u_char *inp, int len);
00064 static void fsm_rconfack(fsm *f, int id, u_char *inp, int len);
00065 static void fsm_rconfnakrej(fsm *f, int code, int id, u_char *inp, int len);
00066 static void fsm_rtermreq(fsm *f, int id, u_char *p, int len);
00067 static void fsm_rtermack(fsm *f);
00068 static void fsm_rcoderej(fsm *f, u_char *inp, int len);
00069 static void fsm_sconfreq(fsm *f, int retransmit);
00070 
00071 #define PROTO_NAME(f)   ((f)->callbacks->proto_name)
00072 
00073 /*
00074  * fsm_init - Initialize fsm.
00075  *
00076  * Initialize fsm state.
00077  */
00078 void fsm_init(fsm *f) {
00079     ppp_pcb *pcb = f->pcb;
00080     f->state = PPP_FSM_INITIAL;
00081     f->flags = 0;
00082     f->id = 0;              /* XXX Start with random id? */
00083     f->maxnakloops = pcb->settings.fsm_max_nak_loops;
00084     f->term_reason_len = 0;
00085 }
00086 
00087 
00088 /*
00089  * fsm_lowerup - The lower layer is up.
00090  */
00091 void fsm_lowerup(fsm *f) {
00092     switch( f->state ){
00093     case PPP_FSM_INITIAL:
00094     f->state = PPP_FSM_CLOSED;
00095     break;
00096 
00097     case PPP_FSM_STARTING:
00098     if( f->flags & OPT_SILENT )
00099         f->state = PPP_FSM_STOPPED;
00100     else {
00101         /* Send an initial configure-request */
00102         fsm_sconfreq(f, 0);
00103         f->state = PPP_FSM_REQSENT;
00104     }
00105     break;
00106 
00107     default:
00108     FSMDEBUG(("%s: Up event in state %d!", PROTO_NAME(f), f->state));
00109     /* no break */
00110     }
00111 }
00112 
00113 
00114 /*
00115  * fsm_lowerdown - The lower layer is down.
00116  *
00117  * Cancel all timeouts and inform upper layers.
00118  */
00119 void fsm_lowerdown(fsm *f) {
00120     switch( f->state ){
00121     case PPP_FSM_CLOSED:
00122     f->state = PPP_FSM_INITIAL;
00123     break;
00124 
00125     case PPP_FSM_STOPPED:
00126     f->state = PPP_FSM_STARTING;
00127     if( f->callbacks->starting )
00128         (*f->callbacks->starting)(f);
00129     break;
00130 
00131     case PPP_FSM_CLOSING:
00132     f->state = PPP_FSM_INITIAL;
00133     UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */
00134     break;
00135 
00136     case PPP_FSM_STOPPING:
00137     case PPP_FSM_REQSENT:
00138     case PPP_FSM_ACKRCVD:
00139     case PPP_FSM_ACKSENT:
00140     f->state = PPP_FSM_STARTING;
00141     UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */
00142     break;
00143 
00144     case PPP_FSM_OPENED:
00145     if( f->callbacks->down )
00146         (*f->callbacks->down)(f);
00147     f->state = PPP_FSM_STARTING;
00148     break;
00149 
00150     default:
00151     FSMDEBUG(("%s: Down event in state %d!", PROTO_NAME(f), f->state));
00152     /* no break */
00153     }
00154 }
00155 
00156 
00157 /*
00158  * fsm_open - Link is allowed to come up.
00159  */
00160 void fsm_open(fsm *f) {
00161     switch( f->state ){
00162     case PPP_FSM_INITIAL:
00163     f->state = PPP_FSM_STARTING;
00164     if( f->callbacks->starting )
00165         (*f->callbacks->starting)(f);
00166     break;
00167 
00168     case PPP_FSM_CLOSED:
00169     if( f->flags & OPT_SILENT )
00170         f->state = PPP_FSM_STOPPED;
00171     else {
00172         /* Send an initial configure-request */
00173         fsm_sconfreq(f, 0);
00174         f->state = PPP_FSM_REQSENT;
00175     }
00176     break;
00177 
00178     case PPP_FSM_CLOSING:
00179     f->state = PPP_FSM_STOPPING;
00180     /* fall through */
00181     /* no break */
00182     case PPP_FSM_STOPPED:
00183     case PPP_FSM_OPENED:
00184     if( f->flags & OPT_RESTART ){
00185         fsm_lowerdown(f);
00186         fsm_lowerup(f);
00187     }
00188     break;
00189     default:
00190     break;
00191     }
00192 }
00193 
00194 /*
00195  * terminate_layer - Start process of shutting down the FSM
00196  *
00197  * Cancel any timeout running, notify upper layers we're done, and
00198  * send a terminate-request message as configured.
00199  */
00200 static void terminate_layer(fsm *f, int nextstate) {
00201     ppp_pcb *pcb = f->pcb;
00202 
00203     if( f->state != PPP_FSM_OPENED )
00204     UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */
00205     else if( f->callbacks->down )
00206     (*f->callbacks->down)(f);   /* Inform upper layers we're down */
00207 
00208     /* Init restart counter and send Terminate-Request */
00209     f->retransmits = pcb->settings.fsm_max_term_transmits;
00210     fsm_sdata(f, TERMREQ, f->reqid = ++f->id,
00211           (const u_char *) f->term_reason, f->term_reason_len);
00212 
00213     if (f->retransmits == 0) {
00214     /*
00215      * User asked for no terminate requests at all; just close it.
00216      * We've already fired off one Terminate-Request just to be nice
00217      * to the peer, but we're not going to wait for a reply.
00218      */
00219     f->state = nextstate == PPP_FSM_CLOSING ? PPP_FSM_CLOSED : PPP_FSM_STOPPED;
00220     if( f->callbacks->finished )
00221         (*f->callbacks->finished)(f);
00222     return;
00223     }
00224 
00225     TIMEOUT(fsm_timeout, f, pcb->settings.fsm_timeout_time);
00226     --f->retransmits;
00227 
00228     f->state = nextstate;
00229 }
00230 
00231 /*
00232  * fsm_close - Start closing connection.
00233  *
00234  * Cancel timeouts and either initiate close or possibly go directly to
00235  * the PPP_FSM_CLOSED state.
00236  */
00237 void fsm_close(fsm *f, const char *reason) {
00238     f->term_reason = reason;
00239     f->term_reason_len = (reason == NULL? 0: LWIP_MIN(strlen(reason), 0xFF) );
00240     switch( f->state ){
00241     case PPP_FSM_STARTING:
00242     f->state = PPP_FSM_INITIAL;
00243     break;
00244     case PPP_FSM_STOPPED:
00245     f->state = PPP_FSM_CLOSED;
00246     break;
00247     case PPP_FSM_STOPPING:
00248     f->state = PPP_FSM_CLOSING;
00249     break;
00250 
00251     case PPP_FSM_REQSENT:
00252     case PPP_FSM_ACKRCVD:
00253     case PPP_FSM_ACKSENT:
00254     case PPP_FSM_OPENED:
00255     terminate_layer(f, PPP_FSM_CLOSING);
00256     break;
00257     default:
00258     break;
00259     }
00260 }
00261 
00262 
00263 /*
00264  * fsm_timeout - Timeout expired.
00265  */
00266 static void fsm_timeout(void *arg) {
00267     fsm *f = (fsm *) arg;
00268     ppp_pcb *pcb = f->pcb;
00269 
00270     switch (f->state) {
00271     case PPP_FSM_CLOSING:
00272     case PPP_FSM_STOPPING:
00273     if( f->retransmits <= 0 ){
00274         /*
00275          * We've waited for an ack long enough.  Peer probably heard us.
00276          */
00277         f->state = (f->state == PPP_FSM_CLOSING)? PPP_FSM_CLOSED: PPP_FSM_STOPPED;
00278         if( f->callbacks->finished )
00279         (*f->callbacks->finished)(f);
00280     } else {
00281         /* Send Terminate-Request */
00282         fsm_sdata(f, TERMREQ, f->reqid = ++f->id,
00283               (const u_char *) f->term_reason, f->term_reason_len);
00284         TIMEOUT(fsm_timeout, f, pcb->settings.fsm_timeout_time);
00285         --f->retransmits;
00286     }
00287     break;
00288 
00289     case PPP_FSM_REQSENT:
00290     case PPP_FSM_ACKRCVD:
00291     case PPP_FSM_ACKSENT:
00292     if (f->retransmits <= 0) {
00293         ppp_warn("%s: timeout sending Config-Requests", PROTO_NAME(f));
00294         f->state = PPP_FSM_STOPPED;
00295         if( (f->flags & OPT_PASSIVE) == 0 && f->callbacks->finished )
00296         (*f->callbacks->finished)(f);
00297 
00298     } else {
00299         /* Retransmit the configure-request */
00300         if (f->callbacks->retransmit)
00301         (*f->callbacks->retransmit)(f);
00302         fsm_sconfreq(f, 1);     /* Re-send Configure-Request */
00303         if( f->state == PPP_FSM_ACKRCVD )
00304         f->state = PPP_FSM_REQSENT;
00305     }
00306     break;
00307 
00308     default:
00309     FSMDEBUG(("%s: Timeout event in state %d!", PROTO_NAME(f), f->state));
00310     /* no break */
00311     }
00312 }
00313 
00314 
00315 /*
00316  * fsm_input - Input packet.
00317  */
00318 void fsm_input(fsm *f, u_char *inpacket, int l) {
00319     u_char *inp;
00320     u_char code, id;
00321     int len;
00322 
00323     /*
00324      * Parse header (code, id and length).
00325      * If packet too short, drop it.
00326      */
00327     inp = inpacket;
00328     if (l < HEADERLEN) {
00329     FSMDEBUG(("fsm_input(%x): Rcvd short header.", f->protocol));
00330     return;
00331     }
00332     GETCHAR(code, inp);
00333     GETCHAR(id, inp);
00334     GETSHORT(len, inp);
00335     if (len < HEADERLEN) {
00336     FSMDEBUG(("fsm_input(%x): Rcvd illegal length.", f->protocol));
00337     return;
00338     }
00339     if (len > l) {
00340     FSMDEBUG(("fsm_input(%x): Rcvd short packet.", f->protocol));
00341     return;
00342     }
00343     len -= HEADERLEN;       /* subtract header length */
00344 
00345     if( f->state == PPP_FSM_INITIAL || f->state == PPP_FSM_STARTING ){
00346     FSMDEBUG(("fsm_input(%x): Rcvd packet in state %d.",
00347           f->protocol, f->state));
00348     return;
00349     }
00350 
00351     /*
00352      * Action depends on code.
00353      */
00354     switch (code) {
00355     case CONFREQ:
00356     fsm_rconfreq(f, id, inp, len);
00357     break;
00358     
00359     case CONFACK:
00360     fsm_rconfack(f, id, inp, len);
00361     break;
00362     
00363     case CONFNAK:
00364     case CONFREJ:
00365     fsm_rconfnakrej(f, code, id, inp, len);
00366     break;
00367     
00368     case TERMREQ:
00369     fsm_rtermreq(f, id, inp, len);
00370     break;
00371     
00372     case TERMACK:
00373     fsm_rtermack(f);
00374     break;
00375     
00376     case CODEREJ:
00377     fsm_rcoderej(f, inp, len);
00378     break;
00379     
00380     default:
00381     if( !f->callbacks->extcode
00382        || !(*f->callbacks->extcode)(f, code, id, inp, len) )
00383         fsm_sdata(f, CODEREJ, ++f->id, inpacket, len + HEADERLEN);
00384     break;
00385     }
00386 }
00387 
00388 
00389 /*
00390  * fsm_rconfreq - Receive Configure-Request.
00391  */
00392 static void fsm_rconfreq(fsm *f, u_char id, u_char *inp, int len) {
00393     int code, reject_if_disagree;
00394 
00395     switch( f->state ){
00396     case PPP_FSM_CLOSED:
00397     /* Go away, we're closed */
00398     fsm_sdata(f, TERMACK, id, NULL, 0);
00399     return;
00400     case PPP_FSM_CLOSING:
00401     case PPP_FSM_STOPPING:
00402     return;
00403 
00404     case PPP_FSM_OPENED:
00405     /* Go down and restart negotiation */
00406     if( f->callbacks->down )
00407         (*f->callbacks->down)(f);   /* Inform upper layers */
00408     fsm_sconfreq(f, 0);     /* Send initial Configure-Request */
00409     f->state = PPP_FSM_REQSENT;
00410     break;
00411 
00412     case PPP_FSM_STOPPED:
00413     /* Negotiation started by our peer */
00414     fsm_sconfreq(f, 0);     /* Send initial Configure-Request */
00415     f->state = PPP_FSM_REQSENT;
00416     break;
00417     default:
00418     break;
00419     }
00420 
00421     /*
00422      * Pass the requested configuration options
00423      * to protocol-specific code for checking.
00424      */
00425     if (f->callbacks->reqci){       /* Check CI */
00426     reject_if_disagree = (f->nakloops >= f->maxnakloops);
00427     code = (*f->callbacks->reqci)(f, inp, &len, reject_if_disagree);
00428     } else if (len)
00429     code = CONFREJ;         /* Reject all CI */
00430     else
00431     code = CONFACK;
00432 
00433     /* send the Ack, Nak or Rej to the peer */
00434     fsm_sdata(f, code, id, inp, len);
00435 
00436     if (code == CONFACK) {
00437     if (f->state == PPP_FSM_ACKRCVD) {
00438         UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */
00439         f->state = PPP_FSM_OPENED;
00440         if (f->callbacks->up)
00441         (*f->callbacks->up)(f); /* Inform upper layers */
00442     } else
00443         f->state = PPP_FSM_ACKSENT;
00444     f->nakloops = 0;
00445 
00446     } else {
00447     /* we sent CONFACK or CONFREJ */
00448     if (f->state != PPP_FSM_ACKRCVD)
00449         f->state = PPP_FSM_REQSENT;
00450     if( code == CONFNAK )
00451         ++f->nakloops;
00452     }
00453 }
00454 
00455 
00456 /*
00457  * fsm_rconfack - Receive Configure-Ack.
00458  */
00459 static void fsm_rconfack(fsm *f, int id, u_char *inp, int len) {
00460     ppp_pcb *pcb = f->pcb;
00461 
00462     if (id != f->reqid || f->seen_ack)      /* Expected id? */
00463     return;                 /* Nope, toss... */
00464     if( !(f->callbacks->ackci? (*f->callbacks->ackci)(f, inp, len):
00465       (len == 0)) ){
00466     /* Ack is bad - ignore it */
00467     ppp_error("Received bad configure-ack: %P", inp, len);
00468     return;
00469     }
00470     f->seen_ack = 1;
00471     f->rnakloops = 0;
00472 
00473     switch (f->state) {
00474     case PPP_FSM_CLOSED:
00475     case PPP_FSM_STOPPED:
00476     fsm_sdata(f, TERMACK, id, NULL, 0);
00477     break;
00478 
00479     case PPP_FSM_REQSENT:
00480     f->state = PPP_FSM_ACKRCVD;
00481     f->retransmits = pcb->settings.fsm_max_conf_req_transmits;
00482     break;
00483 
00484     case PPP_FSM_ACKRCVD:
00485     /* Huh? an extra valid Ack? oh well... */
00486     UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */
00487     fsm_sconfreq(f, 0);
00488     f->state = PPP_FSM_REQSENT;
00489     break;
00490 
00491     case PPP_FSM_ACKSENT:
00492     UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */
00493     f->state = PPP_FSM_OPENED;
00494     f->retransmits = pcb->settings.fsm_max_conf_req_transmits;
00495     if (f->callbacks->up)
00496         (*f->callbacks->up)(f); /* Inform upper layers */
00497     break;
00498 
00499     case PPP_FSM_OPENED:
00500     /* Go down and restart negotiation */
00501     if (f->callbacks->down)
00502         (*f->callbacks->down)(f);   /* Inform upper layers */
00503     fsm_sconfreq(f, 0);     /* Send initial Configure-Request */
00504     f->state = PPP_FSM_REQSENT;
00505     break;
00506     default:
00507     break;
00508     }
00509 }
00510 
00511 
00512 /*
00513  * fsm_rconfnakrej - Receive Configure-Nak or Configure-Reject.
00514  */
00515 static void fsm_rconfnakrej(fsm *f, int code, int id, u_char *inp, int len) {
00516     int ret;
00517     int treat_as_reject;
00518 
00519     if (id != f->reqid || f->seen_ack)  /* Expected id? */
00520     return;             /* Nope, toss... */
00521 
00522     if (code == CONFNAK) {
00523     ++f->rnakloops;
00524     treat_as_reject = (f->rnakloops >= f->maxnakloops);
00525     if (f->callbacks->nakci == NULL
00526         || !(ret = f->callbacks->nakci(f, inp, len, treat_as_reject))) {
00527         ppp_error("Received bad configure-nak: %P", inp, len);
00528         return;
00529     }
00530     } else {
00531     f->rnakloops = 0;
00532     if (f->callbacks->rejci == NULL
00533         || !(ret = f->callbacks->rejci(f, inp, len))) {
00534         ppp_error("Received bad configure-rej: %P", inp, len);
00535         return;
00536     }
00537     }
00538 
00539     f->seen_ack = 1;
00540 
00541     switch (f->state) {
00542     case PPP_FSM_CLOSED:
00543     case PPP_FSM_STOPPED:
00544     fsm_sdata(f, TERMACK, id, NULL, 0);
00545     break;
00546 
00547     case PPP_FSM_REQSENT:
00548     case PPP_FSM_ACKSENT:
00549     /* They didn't agree to what we wanted - try another request */
00550     UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */
00551     if (ret < 0)
00552         f->state = PPP_FSM_STOPPED;     /* kludge for stopping CCP */
00553     else
00554         fsm_sconfreq(f, 0);     /* Send Configure-Request */
00555     break;
00556 
00557     case PPP_FSM_ACKRCVD:
00558     /* Got a Nak/reject when we had already had an Ack?? oh well... */
00559     UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */
00560     fsm_sconfreq(f, 0);
00561     f->state = PPP_FSM_REQSENT;
00562     break;
00563 
00564     case PPP_FSM_OPENED:
00565     /* Go down and restart negotiation */
00566     if (f->callbacks->down)
00567         (*f->callbacks->down)(f);   /* Inform upper layers */
00568     fsm_sconfreq(f, 0);     /* Send initial Configure-Request */
00569     f->state = PPP_FSM_REQSENT;
00570     break;
00571     default:
00572     break;
00573     }
00574 }
00575 
00576 
00577 /*
00578  * fsm_rtermreq - Receive Terminate-Req.
00579  */
00580 static void fsm_rtermreq(fsm *f, int id, u_char *p, int len) {
00581     ppp_pcb *pcb = f->pcb;
00582 
00583     switch (f->state) {
00584     case PPP_FSM_ACKRCVD:
00585     case PPP_FSM_ACKSENT:
00586     f->state = PPP_FSM_REQSENT;     /* Start over but keep trying */
00587     break;
00588 
00589     case PPP_FSM_OPENED:
00590     if (len > 0) {
00591         ppp_info("%s terminated by peer (%0.*v)", PROTO_NAME(f), len, p);
00592     } else
00593         ppp_info("%s terminated by peer", PROTO_NAME(f));
00594     f->retransmits = 0;
00595     f->state = PPP_FSM_STOPPING;
00596     if (f->callbacks->down)
00597         (*f->callbacks->down)(f);   /* Inform upper layers */
00598     TIMEOUT(fsm_timeout, f, pcb->settings.fsm_timeout_time);
00599     break;
00600     default:
00601     break;
00602     }
00603 
00604     fsm_sdata(f, TERMACK, id, NULL, 0);
00605 }
00606 
00607 
00608 /*
00609  * fsm_rtermack - Receive Terminate-Ack.
00610  */
00611 static void fsm_rtermack(fsm *f) {
00612     switch (f->state) {
00613     case PPP_FSM_CLOSING:
00614     UNTIMEOUT(fsm_timeout, f);
00615     f->state = PPP_FSM_CLOSED;
00616     if( f->callbacks->finished )
00617         (*f->callbacks->finished)(f);
00618     break;
00619     case PPP_FSM_STOPPING:
00620     UNTIMEOUT(fsm_timeout, f);
00621     f->state = PPP_FSM_STOPPED;
00622     if( f->callbacks->finished )
00623         (*f->callbacks->finished)(f);
00624     break;
00625 
00626     case PPP_FSM_ACKRCVD:
00627     f->state = PPP_FSM_REQSENT;
00628     break;
00629 
00630     case PPP_FSM_OPENED:
00631     if (f->callbacks->down)
00632         (*f->callbacks->down)(f);   /* Inform upper layers */
00633     fsm_sconfreq(f, 0);
00634     f->state = PPP_FSM_REQSENT;
00635     break;
00636     default:
00637     break;
00638     }
00639 }
00640 
00641 
00642 /*
00643  * fsm_rcoderej - Receive an Code-Reject.
00644  */
00645 static void fsm_rcoderej(fsm *f, u_char *inp, int len) {
00646     u_char code, id;
00647 
00648     if (len < HEADERLEN) {
00649     FSMDEBUG(("fsm_rcoderej: Rcvd short Code-Reject packet!"));
00650     return;
00651     }
00652     GETCHAR(code, inp);
00653     GETCHAR(id, inp);
00654     ppp_warn("%s: Rcvd Code-Reject for code %d, id %d", PROTO_NAME(f), code, id);
00655 
00656     if( f->state == PPP_FSM_ACKRCVD )
00657     f->state = PPP_FSM_REQSENT;
00658 }
00659 
00660 
00661 /*
00662  * fsm_protreject - Peer doesn't speak this protocol.
00663  *
00664  * Treat this as a catastrophic error (RXJ-).
00665  */
00666 void fsm_protreject(fsm *f) {
00667     switch( f->state ){
00668     case PPP_FSM_CLOSING:
00669     UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */
00670     /* fall through */
00671     /* no break */
00672     case PPP_FSM_CLOSED:
00673     f->state = PPP_FSM_CLOSED;
00674     if( f->callbacks->finished )
00675         (*f->callbacks->finished)(f);
00676     break;
00677 
00678     case PPP_FSM_STOPPING:
00679     case PPP_FSM_REQSENT:
00680     case PPP_FSM_ACKRCVD:
00681     case PPP_FSM_ACKSENT:
00682     UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */
00683     /* fall through */
00684     /* no break */
00685     case PPP_FSM_STOPPED:
00686     f->state = PPP_FSM_STOPPED;
00687     if( f->callbacks->finished )
00688         (*f->callbacks->finished)(f);
00689     break;
00690 
00691     case PPP_FSM_OPENED:
00692     terminate_layer(f, PPP_FSM_STOPPING);
00693     break;
00694 
00695     default:
00696     FSMDEBUG(("%s: Protocol-reject event in state %d!",
00697           PROTO_NAME(f), f->state));
00698     /* no break */
00699     }
00700 }
00701 
00702 
00703 /*
00704  * fsm_sconfreq - Send a Configure-Request.
00705  */
00706 static void fsm_sconfreq(fsm *f, int retransmit) {
00707     ppp_pcb *pcb = f->pcb;
00708     struct pbuf *p;
00709     u_char *outp;
00710     int cilen;
00711 
00712     if( f->state != PPP_FSM_REQSENT && f->state != PPP_FSM_ACKRCVD && f->state != PPP_FSM_ACKSENT ){
00713     /* Not currently negotiating - reset options */
00714     if( f->callbacks->resetci )
00715         (*f->callbacks->resetci)(f);
00716     f->nakloops = 0;
00717     f->rnakloops = 0;
00718     }
00719 
00720     if( !retransmit ){
00721     /* New request - reset retransmission counter, use new ID */
00722     f->retransmits = pcb->settings.fsm_max_conf_req_transmits;
00723     f->reqid = ++f->id;
00724     }
00725 
00726     f->seen_ack = 0;
00727 
00728     /*
00729      * Make up the request packet
00730      */
00731     if( f->callbacks->cilen && f->callbacks->addci ){
00732     cilen = (*f->callbacks->cilen)(f);
00733     if( cilen > pcb->peer_mru - HEADERLEN )
00734         cilen = pcb->peer_mru - HEADERLEN;
00735     } else
00736     cilen = 0;
00737 
00738     p = pbuf_alloc(PBUF_RAW, (u16_t)(cilen + HEADERLEN + PPP_HDRLEN), PPP_CTRL_PBUF_TYPE);
00739     if(NULL == p)
00740         return;
00741     if(p->tot_len != p->len) {
00742         pbuf_free(p);
00743         return;
00744     }
00745 
00746     /* send the request to our peer */
00747     outp = (u_char*)p->payload;
00748     MAKEHEADER(outp, f->protocol);
00749     PUTCHAR(CONFREQ, outp);
00750     PUTCHAR(f->reqid, outp);
00751     PUTSHORT(cilen + HEADERLEN, outp);
00752     if (cilen != 0) {
00753     (*f->callbacks->addci)(f, outp, &cilen);
00754     LWIP_ASSERT("cilen == p->len - HEADERLEN - PPP_HDRLEN", cilen == p->len - HEADERLEN - PPP_HDRLEN);
00755     }
00756 
00757     ppp_write(pcb, p);
00758 
00759     /* start the retransmit timer */
00760     --f->retransmits;
00761     TIMEOUT(fsm_timeout, f, pcb->settings.fsm_timeout_time);
00762 }
00763 
00764 
00765 /*
00766  * fsm_sdata - Send some data.
00767  *
00768  * Used for all packets sent to our peer by this module.
00769  */
00770 void fsm_sdata(fsm *f, u_char code, u_char id, const u_char *data, int datalen) {
00771     ppp_pcb *pcb = f->pcb;
00772     struct pbuf *p;
00773     u_char *outp;
00774     int outlen;
00775 
00776     /* Adjust length to be smaller than MTU */
00777     if (datalen > pcb->peer_mru - HEADERLEN)
00778     datalen = pcb->peer_mru - HEADERLEN;
00779     outlen = datalen + HEADERLEN;
00780 
00781     p = pbuf_alloc(PBUF_RAW, (u16_t)(outlen + PPP_HDRLEN), PPP_CTRL_PBUF_TYPE);
00782     if(NULL == p)
00783         return;
00784     if(p->tot_len != p->len) {
00785         pbuf_free(p);
00786         return;
00787     }
00788 
00789     outp = (u_char*)p->payload;
00790     if (datalen) /* && data != outp + PPP_HDRLEN + HEADERLEN)  -- was only for fsm_sconfreq() */
00791     MEMCPY(outp + PPP_HDRLEN + HEADERLEN, data, datalen);
00792     MAKEHEADER(outp, f->protocol);
00793     PUTCHAR(code, outp);
00794     PUTCHAR(id, outp);
00795     PUTSHORT(outlen, outp);
00796     ppp_write(pcb, p);
00797 }
00798 
00799 #endif /* PPP_SUPPORT */