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.
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 */
Generated on Tue Jul 12 2022 21:10:25 by 1.7.2