Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of lwip by
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 */
Generated on Tue Jul 12 2022 11:29:36 by
