This library is stripped down version of NetServices library. HTTP server and client function is NOT supported.

Dependents:   imu-daq-eth

Committer:
idinor
Date:
Wed Jul 20 11:45:39 2011 +0000
Revision:
0:dcf3c92487ca

        

Who changed what in which revision?

UserRevisionLine numberNew contents of line
idinor 0:dcf3c92487ca 1 /*****************************************************************************
idinor 0:dcf3c92487ca 2 * fsm.c - Network Control Protocol Finite State Machine program file.
idinor 0:dcf3c92487ca 3 *
idinor 0:dcf3c92487ca 4 * Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
idinor 0:dcf3c92487ca 5 * portions Copyright (c) 1997 by Global Election Systems Inc.
idinor 0:dcf3c92487ca 6 *
idinor 0:dcf3c92487ca 7 * The authors hereby grant permission to use, copy, modify, distribute,
idinor 0:dcf3c92487ca 8 * and license this software and its documentation for any purpose, provided
idinor 0:dcf3c92487ca 9 * that existing copyright notices are retained in all copies and that this
idinor 0:dcf3c92487ca 10 * notice and the following disclaimer are included verbatim in any
idinor 0:dcf3c92487ca 11 * distributions. No written agreement, license, or royalty fee is required
idinor 0:dcf3c92487ca 12 * for any of the authorized uses.
idinor 0:dcf3c92487ca 13 *
idinor 0:dcf3c92487ca 14 * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR
idinor 0:dcf3c92487ca 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
idinor 0:dcf3c92487ca 16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
idinor 0:dcf3c92487ca 17 * IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
idinor 0:dcf3c92487ca 18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
idinor 0:dcf3c92487ca 19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
idinor 0:dcf3c92487ca 20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
idinor 0:dcf3c92487ca 21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
idinor 0:dcf3c92487ca 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
idinor 0:dcf3c92487ca 23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
idinor 0:dcf3c92487ca 24 *
idinor 0:dcf3c92487ca 25 ******************************************************************************
idinor 0:dcf3c92487ca 26 * REVISION HISTORY
idinor 0:dcf3c92487ca 27 *
idinor 0:dcf3c92487ca 28 * 03-01-01 Marc Boucher <marc@mbsi.ca>
idinor 0:dcf3c92487ca 29 * Ported to lwIP.
idinor 0:dcf3c92487ca 30 * 97-12-01 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.
idinor 0:dcf3c92487ca 31 * Original based on BSD fsm.c.
idinor 0:dcf3c92487ca 32 *****************************************************************************/
idinor 0:dcf3c92487ca 33 /*
idinor 0:dcf3c92487ca 34 * fsm.c - {Link, IP} Control Protocol Finite State Machine.
idinor 0:dcf3c92487ca 35 *
idinor 0:dcf3c92487ca 36 * Copyright (c) 1989 Carnegie Mellon University.
idinor 0:dcf3c92487ca 37 * All rights reserved.
idinor 0:dcf3c92487ca 38 *
idinor 0:dcf3c92487ca 39 * Redistribution and use in source and binary forms are permitted
idinor 0:dcf3c92487ca 40 * provided that the above copyright notice and this paragraph are
idinor 0:dcf3c92487ca 41 * duplicated in all such forms and that any documentation,
idinor 0:dcf3c92487ca 42 * advertising materials, and other materials related to such
idinor 0:dcf3c92487ca 43 * distribution and use acknowledge that the software was developed
idinor 0:dcf3c92487ca 44 * by Carnegie Mellon University. The name of the
idinor 0:dcf3c92487ca 45 * University may not be used to endorse or promote products derived
idinor 0:dcf3c92487ca 46 * from this software without specific prior written permission.
idinor 0:dcf3c92487ca 47 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
idinor 0:dcf3c92487ca 48 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
idinor 0:dcf3c92487ca 49 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
idinor 0:dcf3c92487ca 50 */
idinor 0:dcf3c92487ca 51
idinor 0:dcf3c92487ca 52 /*
idinor 0:dcf3c92487ca 53 * TODO:
idinor 0:dcf3c92487ca 54 * Randomize fsm id on link/init.
idinor 0:dcf3c92487ca 55 * Deal with variable outgoing MTU.
idinor 0:dcf3c92487ca 56 */
idinor 0:dcf3c92487ca 57
idinor 0:dcf3c92487ca 58 #include "lwip/opt.h"
idinor 0:dcf3c92487ca 59
idinor 0:dcf3c92487ca 60 #if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */
idinor 0:dcf3c92487ca 61
idinor 0:dcf3c92487ca 62 #include "ppp.h"
idinor 0:dcf3c92487ca 63 #include "pppdebug.h"
idinor 0:dcf3c92487ca 64
idinor 0:dcf3c92487ca 65 #include "fsm.h"
idinor 0:dcf3c92487ca 66
idinor 0:dcf3c92487ca 67 #include <string.h>
idinor 0:dcf3c92487ca 68
idinor 0:dcf3c92487ca 69 #if PPP_DEBUG
idinor 0:dcf3c92487ca 70 static const char *ppperr_strerr[] = {
idinor 0:dcf3c92487ca 71 "LS_INITIAL", /* LS_INITIAL 0 */
idinor 0:dcf3c92487ca 72 "LS_STARTING", /* LS_STARTING 1 */
idinor 0:dcf3c92487ca 73 "LS_CLOSED", /* LS_CLOSED 2 */
idinor 0:dcf3c92487ca 74 "LS_STOPPED", /* LS_STOPPED 3 */
idinor 0:dcf3c92487ca 75 "LS_CLOSING", /* LS_CLOSING 4 */
idinor 0:dcf3c92487ca 76 "LS_STOPPING", /* LS_STOPPING 5 */
idinor 0:dcf3c92487ca 77 "LS_REQSENT", /* LS_REQSENT 6 */
idinor 0:dcf3c92487ca 78 "LS_ACKRCVD", /* LS_ACKRCVD 7 */
idinor 0:dcf3c92487ca 79 "LS_ACKSENT", /* LS_ACKSENT 8 */
idinor 0:dcf3c92487ca 80 "LS_OPENED" /* LS_OPENED 9 */
idinor 0:dcf3c92487ca 81 };
idinor 0:dcf3c92487ca 82 #endif /* PPP_DEBUG */
idinor 0:dcf3c92487ca 83
idinor 0:dcf3c92487ca 84 static void fsm_timeout (void *);
idinor 0:dcf3c92487ca 85 static void fsm_rconfreq (fsm *, u_char, u_char *, int);
idinor 0:dcf3c92487ca 86 static void fsm_rconfack (fsm *, int, u_char *, int);
idinor 0:dcf3c92487ca 87 static void fsm_rconfnakrej (fsm *, int, int, u_char *, int);
idinor 0:dcf3c92487ca 88 static void fsm_rtermreq (fsm *, int, u_char *, int);
idinor 0:dcf3c92487ca 89 static void fsm_rtermack (fsm *);
idinor 0:dcf3c92487ca 90 static void fsm_rcoderej (fsm *, u_char *, int);
idinor 0:dcf3c92487ca 91 static void fsm_sconfreq (fsm *, int);
idinor 0:dcf3c92487ca 92
idinor 0:dcf3c92487ca 93 #define PROTO_NAME(f) ((f)->callbacks->proto_name)
idinor 0:dcf3c92487ca 94
idinor 0:dcf3c92487ca 95 int peer_mru[NUM_PPP];
idinor 0:dcf3c92487ca 96
idinor 0:dcf3c92487ca 97
idinor 0:dcf3c92487ca 98 /*
idinor 0:dcf3c92487ca 99 * fsm_init - Initialize fsm.
idinor 0:dcf3c92487ca 100 *
idinor 0:dcf3c92487ca 101 * Initialize fsm state.
idinor 0:dcf3c92487ca 102 */
idinor 0:dcf3c92487ca 103 void
idinor 0:dcf3c92487ca 104 fsm_init(fsm *f)
idinor 0:dcf3c92487ca 105 {
idinor 0:dcf3c92487ca 106 f->state = LS_INITIAL;
idinor 0:dcf3c92487ca 107 f->flags = 0;
idinor 0:dcf3c92487ca 108 f->id = 0; /* XXX Start with random id? */
idinor 0:dcf3c92487ca 109 f->timeouttime = FSM_DEFTIMEOUT;
idinor 0:dcf3c92487ca 110 f->maxconfreqtransmits = FSM_DEFMAXCONFREQS;
idinor 0:dcf3c92487ca 111 f->maxtermtransmits = FSM_DEFMAXTERMREQS;
idinor 0:dcf3c92487ca 112 f->maxnakloops = FSM_DEFMAXNAKLOOPS;
idinor 0:dcf3c92487ca 113 f->term_reason_len = 0;
idinor 0:dcf3c92487ca 114 }
idinor 0:dcf3c92487ca 115
idinor 0:dcf3c92487ca 116
idinor 0:dcf3c92487ca 117 /*
idinor 0:dcf3c92487ca 118 * fsm_lowerup - The lower layer is up.
idinor 0:dcf3c92487ca 119 */
idinor 0:dcf3c92487ca 120 void
idinor 0:dcf3c92487ca 121 fsm_lowerup(fsm *f)
idinor 0:dcf3c92487ca 122 {
idinor 0:dcf3c92487ca 123 int oldState = f->state;
idinor 0:dcf3c92487ca 124
idinor 0:dcf3c92487ca 125 LWIP_UNUSED_ARG(oldState);
idinor 0:dcf3c92487ca 126
idinor 0:dcf3c92487ca 127 switch( f->state ) {
idinor 0:dcf3c92487ca 128 case LS_INITIAL:
idinor 0:dcf3c92487ca 129 f->state = LS_CLOSED;
idinor 0:dcf3c92487ca 130 break;
idinor 0:dcf3c92487ca 131
idinor 0:dcf3c92487ca 132 case LS_STARTING:
idinor 0:dcf3c92487ca 133 if( f->flags & OPT_SILENT ) {
idinor 0:dcf3c92487ca 134 f->state = LS_STOPPED;
idinor 0:dcf3c92487ca 135 } else {
idinor 0:dcf3c92487ca 136 /* Send an initial configure-request */
idinor 0:dcf3c92487ca 137 fsm_sconfreq(f, 0);
idinor 0:dcf3c92487ca 138 f->state = LS_REQSENT;
idinor 0:dcf3c92487ca 139 }
idinor 0:dcf3c92487ca 140 break;
idinor 0:dcf3c92487ca 141
idinor 0:dcf3c92487ca 142 default:
idinor 0:dcf3c92487ca 143 FSMDEBUG(LOG_INFO, ("%s: Up event in state %d (%s)!\n",
idinor 0:dcf3c92487ca 144 PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
idinor 0:dcf3c92487ca 145 }
idinor 0:dcf3c92487ca 146
idinor 0:dcf3c92487ca 147 FSMDEBUG(LOG_INFO, ("%s: lowerup state %d (%s) -> %d (%s)\n",
idinor 0:dcf3c92487ca 148 PROTO_NAME(f), oldState, ppperr_strerr[oldState], f->state, ppperr_strerr[f->state]));
idinor 0:dcf3c92487ca 149 }
idinor 0:dcf3c92487ca 150
idinor 0:dcf3c92487ca 151
idinor 0:dcf3c92487ca 152 /*
idinor 0:dcf3c92487ca 153 * fsm_lowerdown - The lower layer is down.
idinor 0:dcf3c92487ca 154 *
idinor 0:dcf3c92487ca 155 * Cancel all timeouts and inform upper layers.
idinor 0:dcf3c92487ca 156 */
idinor 0:dcf3c92487ca 157 void
idinor 0:dcf3c92487ca 158 fsm_lowerdown(fsm *f)
idinor 0:dcf3c92487ca 159 {
idinor 0:dcf3c92487ca 160 int oldState = f->state;
idinor 0:dcf3c92487ca 161
idinor 0:dcf3c92487ca 162 LWIP_UNUSED_ARG(oldState);
idinor 0:dcf3c92487ca 163
idinor 0:dcf3c92487ca 164 switch( f->state ) {
idinor 0:dcf3c92487ca 165 case LS_CLOSED:
idinor 0:dcf3c92487ca 166 f->state = LS_INITIAL;
idinor 0:dcf3c92487ca 167 break;
idinor 0:dcf3c92487ca 168
idinor 0:dcf3c92487ca 169 case LS_STOPPED:
idinor 0:dcf3c92487ca 170 f->state = LS_STARTING;
idinor 0:dcf3c92487ca 171 if( f->callbacks->starting ) {
idinor 0:dcf3c92487ca 172 (*f->callbacks->starting)(f);
idinor 0:dcf3c92487ca 173 }
idinor 0:dcf3c92487ca 174 break;
idinor 0:dcf3c92487ca 175
idinor 0:dcf3c92487ca 176 case LS_CLOSING:
idinor 0:dcf3c92487ca 177 f->state = LS_INITIAL;
idinor 0:dcf3c92487ca 178 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
idinor 0:dcf3c92487ca 179 break;
idinor 0:dcf3c92487ca 180
idinor 0:dcf3c92487ca 181 case LS_STOPPING:
idinor 0:dcf3c92487ca 182 case LS_REQSENT:
idinor 0:dcf3c92487ca 183 case LS_ACKRCVD:
idinor 0:dcf3c92487ca 184 case LS_ACKSENT:
idinor 0:dcf3c92487ca 185 f->state = LS_STARTING;
idinor 0:dcf3c92487ca 186 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
idinor 0:dcf3c92487ca 187 break;
idinor 0:dcf3c92487ca 188
idinor 0:dcf3c92487ca 189 case LS_OPENED:
idinor 0:dcf3c92487ca 190 if( f->callbacks->down ) {
idinor 0:dcf3c92487ca 191 (*f->callbacks->down)(f);
idinor 0:dcf3c92487ca 192 }
idinor 0:dcf3c92487ca 193 f->state = LS_STARTING;
idinor 0:dcf3c92487ca 194 break;
idinor 0:dcf3c92487ca 195
idinor 0:dcf3c92487ca 196 default:
idinor 0:dcf3c92487ca 197 FSMDEBUG(LOG_INFO, ("%s: Down event in state %d (%s)!\n",
idinor 0:dcf3c92487ca 198 PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
idinor 0:dcf3c92487ca 199 }
idinor 0:dcf3c92487ca 200
idinor 0:dcf3c92487ca 201 FSMDEBUG(LOG_INFO, ("%s: lowerdown state %d (%s) -> %d (%s)\n",
idinor 0:dcf3c92487ca 202 PROTO_NAME(f), oldState, ppperr_strerr[oldState], f->state, ppperr_strerr[f->state]));
idinor 0:dcf3c92487ca 203 }
idinor 0:dcf3c92487ca 204
idinor 0:dcf3c92487ca 205
idinor 0:dcf3c92487ca 206 /*
idinor 0:dcf3c92487ca 207 * fsm_open - Link is allowed to come up.
idinor 0:dcf3c92487ca 208 */
idinor 0:dcf3c92487ca 209 void
idinor 0:dcf3c92487ca 210 fsm_open(fsm *f)
idinor 0:dcf3c92487ca 211 {
idinor 0:dcf3c92487ca 212 int oldState = f->state;
idinor 0:dcf3c92487ca 213
idinor 0:dcf3c92487ca 214 LWIP_UNUSED_ARG(oldState);
idinor 0:dcf3c92487ca 215
idinor 0:dcf3c92487ca 216 switch( f->state ) {
idinor 0:dcf3c92487ca 217 case LS_INITIAL:
idinor 0:dcf3c92487ca 218 f->state = LS_STARTING;
idinor 0:dcf3c92487ca 219 if( f->callbacks->starting ) {
idinor 0:dcf3c92487ca 220 (*f->callbacks->starting)(f);
idinor 0:dcf3c92487ca 221 }
idinor 0:dcf3c92487ca 222 break;
idinor 0:dcf3c92487ca 223
idinor 0:dcf3c92487ca 224 case LS_CLOSED:
idinor 0:dcf3c92487ca 225 if( f->flags & OPT_SILENT ) {
idinor 0:dcf3c92487ca 226 f->state = LS_STOPPED;
idinor 0:dcf3c92487ca 227 } else {
idinor 0:dcf3c92487ca 228 /* Send an initial configure-request */
idinor 0:dcf3c92487ca 229 fsm_sconfreq(f, 0);
idinor 0:dcf3c92487ca 230 f->state = LS_REQSENT;
idinor 0:dcf3c92487ca 231 }
idinor 0:dcf3c92487ca 232 break;
idinor 0:dcf3c92487ca 233
idinor 0:dcf3c92487ca 234 case LS_CLOSING:
idinor 0:dcf3c92487ca 235 f->state = LS_STOPPING;
idinor 0:dcf3c92487ca 236 /* fall through */
idinor 0:dcf3c92487ca 237 case LS_STOPPED:
idinor 0:dcf3c92487ca 238 case LS_OPENED:
idinor 0:dcf3c92487ca 239 if( f->flags & OPT_RESTART ) {
idinor 0:dcf3c92487ca 240 fsm_lowerdown(f);
idinor 0:dcf3c92487ca 241 fsm_lowerup(f);
idinor 0:dcf3c92487ca 242 }
idinor 0:dcf3c92487ca 243 break;
idinor 0:dcf3c92487ca 244 }
idinor 0:dcf3c92487ca 245
idinor 0:dcf3c92487ca 246 FSMDEBUG(LOG_INFO, ("%s: open state %d (%s) -> %d (%s)\n",
idinor 0:dcf3c92487ca 247 PROTO_NAME(f), oldState, ppperr_strerr[oldState], f->state, ppperr_strerr[f->state]));
idinor 0:dcf3c92487ca 248 }
idinor 0:dcf3c92487ca 249
idinor 0:dcf3c92487ca 250 #if 0 /* backport pppd 2.4.4b1; */
idinor 0:dcf3c92487ca 251 /*
idinor 0:dcf3c92487ca 252 * terminate_layer - Start process of shutting down the FSM
idinor 0:dcf3c92487ca 253 *
idinor 0:dcf3c92487ca 254 * Cancel any timeout running, notify upper layers we're done, and
idinor 0:dcf3c92487ca 255 * send a terminate-request message as configured.
idinor 0:dcf3c92487ca 256 */
idinor 0:dcf3c92487ca 257 static void
idinor 0:dcf3c92487ca 258 terminate_layer(fsm *f, int nextstate)
idinor 0:dcf3c92487ca 259 {
idinor 0:dcf3c92487ca 260 /* @todo */
idinor 0:dcf3c92487ca 261 }
idinor 0:dcf3c92487ca 262 #endif
idinor 0:dcf3c92487ca 263
idinor 0:dcf3c92487ca 264 /*
idinor 0:dcf3c92487ca 265 * fsm_close - Start closing connection.
idinor 0:dcf3c92487ca 266 *
idinor 0:dcf3c92487ca 267 * Cancel timeouts and either initiate close or possibly go directly to
idinor 0:dcf3c92487ca 268 * the LS_CLOSED state.
idinor 0:dcf3c92487ca 269 */
idinor 0:dcf3c92487ca 270 void
idinor 0:dcf3c92487ca 271 fsm_close(fsm *f, char *reason)
idinor 0:dcf3c92487ca 272 {
idinor 0:dcf3c92487ca 273 int oldState = f->state;
idinor 0:dcf3c92487ca 274
idinor 0:dcf3c92487ca 275 LWIP_UNUSED_ARG(oldState);
idinor 0:dcf3c92487ca 276
idinor 0:dcf3c92487ca 277 f->term_reason = reason;
idinor 0:dcf3c92487ca 278 f->term_reason_len = (reason == NULL ? 0 : (int)strlen(reason));
idinor 0:dcf3c92487ca 279 switch( f->state ) {
idinor 0:dcf3c92487ca 280 case LS_STARTING:
idinor 0:dcf3c92487ca 281 f->state = LS_INITIAL;
idinor 0:dcf3c92487ca 282 break;
idinor 0:dcf3c92487ca 283 case LS_STOPPED:
idinor 0:dcf3c92487ca 284 f->state = LS_CLOSED;
idinor 0:dcf3c92487ca 285 break;
idinor 0:dcf3c92487ca 286 case LS_STOPPING:
idinor 0:dcf3c92487ca 287 f->state = LS_CLOSING;
idinor 0:dcf3c92487ca 288 break;
idinor 0:dcf3c92487ca 289
idinor 0:dcf3c92487ca 290 case LS_REQSENT:
idinor 0:dcf3c92487ca 291 case LS_ACKRCVD:
idinor 0:dcf3c92487ca 292 case LS_ACKSENT:
idinor 0:dcf3c92487ca 293 case LS_OPENED:
idinor 0:dcf3c92487ca 294 if( f->state != LS_OPENED ) {
idinor 0:dcf3c92487ca 295 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
idinor 0:dcf3c92487ca 296 } else if( f->callbacks->down ) {
idinor 0:dcf3c92487ca 297 (*f->callbacks->down)(f); /* Inform upper layers we're down */
idinor 0:dcf3c92487ca 298 }
idinor 0:dcf3c92487ca 299 /* Init restart counter, send Terminate-Request */
idinor 0:dcf3c92487ca 300 f->retransmits = f->maxtermtransmits;
idinor 0:dcf3c92487ca 301 fsm_sdata(f, TERMREQ, f->reqid = ++f->id,
idinor 0:dcf3c92487ca 302 (u_char *) f->term_reason, f->term_reason_len);
idinor 0:dcf3c92487ca 303 TIMEOUT(fsm_timeout, f, f->timeouttime);
idinor 0:dcf3c92487ca 304 --f->retransmits;
idinor 0:dcf3c92487ca 305
idinor 0:dcf3c92487ca 306 f->state = LS_CLOSING;
idinor 0:dcf3c92487ca 307 break;
idinor 0:dcf3c92487ca 308 }
idinor 0:dcf3c92487ca 309
idinor 0:dcf3c92487ca 310 FSMDEBUG(LOG_INFO, ("%s: close reason=%s state %d (%s) -> %d (%s)\n",
idinor 0:dcf3c92487ca 311 PROTO_NAME(f), reason, oldState, ppperr_strerr[oldState], f->state, ppperr_strerr[f->state]));
idinor 0:dcf3c92487ca 312 }
idinor 0:dcf3c92487ca 313
idinor 0:dcf3c92487ca 314
idinor 0:dcf3c92487ca 315 /*
idinor 0:dcf3c92487ca 316 * fsm_timeout - Timeout expired.
idinor 0:dcf3c92487ca 317 */
idinor 0:dcf3c92487ca 318 static void
idinor 0:dcf3c92487ca 319 fsm_timeout(void *arg)
idinor 0:dcf3c92487ca 320 {
idinor 0:dcf3c92487ca 321 fsm *f = (fsm *) arg;
idinor 0:dcf3c92487ca 322
idinor 0:dcf3c92487ca 323 switch (f->state) {
idinor 0:dcf3c92487ca 324 case LS_CLOSING:
idinor 0:dcf3c92487ca 325 case LS_STOPPING:
idinor 0:dcf3c92487ca 326 if( f->retransmits <= 0 ) {
idinor 0:dcf3c92487ca 327 FSMDEBUG(LOG_WARNING, ("%s: timeout sending Terminate-Request state=%d (%s)\n",
idinor 0:dcf3c92487ca 328 PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
idinor 0:dcf3c92487ca 329 /*
idinor 0:dcf3c92487ca 330 * We've waited for an ack long enough. Peer probably heard us.
idinor 0:dcf3c92487ca 331 */
idinor 0:dcf3c92487ca 332 f->state = (f->state == LS_CLOSING)? LS_CLOSED: LS_STOPPED;
idinor 0:dcf3c92487ca 333 if( f->callbacks->finished ) {
idinor 0:dcf3c92487ca 334 (*f->callbacks->finished)(f);
idinor 0:dcf3c92487ca 335 }
idinor 0:dcf3c92487ca 336 } else {
idinor 0:dcf3c92487ca 337 FSMDEBUG(LOG_WARNING, ("%s: timeout resending Terminate-Requests state=%d (%s)\n",
idinor 0:dcf3c92487ca 338 PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
idinor 0:dcf3c92487ca 339 /* Send Terminate-Request */
idinor 0:dcf3c92487ca 340 fsm_sdata(f, TERMREQ, f->reqid = ++f->id,
idinor 0:dcf3c92487ca 341 (u_char *) f->term_reason, f->term_reason_len);
idinor 0:dcf3c92487ca 342 TIMEOUT(fsm_timeout, f, f->timeouttime);
idinor 0:dcf3c92487ca 343 --f->retransmits;
idinor 0:dcf3c92487ca 344 }
idinor 0:dcf3c92487ca 345 break;
idinor 0:dcf3c92487ca 346
idinor 0:dcf3c92487ca 347 case LS_REQSENT:
idinor 0:dcf3c92487ca 348 case LS_ACKRCVD:
idinor 0:dcf3c92487ca 349 case LS_ACKSENT:
idinor 0:dcf3c92487ca 350 if (f->retransmits <= 0) {
idinor 0:dcf3c92487ca 351 FSMDEBUG(LOG_WARNING, ("%s: timeout sending Config-Requests state=%d (%s)\n",
idinor 0:dcf3c92487ca 352 PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
idinor 0:dcf3c92487ca 353 f->state = LS_STOPPED;
idinor 0:dcf3c92487ca 354 if( (f->flags & OPT_PASSIVE) == 0 && f->callbacks->finished ) {
idinor 0:dcf3c92487ca 355 (*f->callbacks->finished)(f);
idinor 0:dcf3c92487ca 356 }
idinor 0:dcf3c92487ca 357 } else {
idinor 0:dcf3c92487ca 358 FSMDEBUG(LOG_WARNING, ("%s: timeout resending Config-Request state=%d (%s)\n",
idinor 0:dcf3c92487ca 359 PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
idinor 0:dcf3c92487ca 360 /* Retransmit the configure-request */
idinor 0:dcf3c92487ca 361 if (f->callbacks->retransmit) {
idinor 0:dcf3c92487ca 362 (*f->callbacks->retransmit)(f);
idinor 0:dcf3c92487ca 363 }
idinor 0:dcf3c92487ca 364 fsm_sconfreq(f, 1); /* Re-send Configure-Request */
idinor 0:dcf3c92487ca 365 if( f->state == LS_ACKRCVD ) {
idinor 0:dcf3c92487ca 366 f->state = LS_REQSENT;
idinor 0:dcf3c92487ca 367 }
idinor 0:dcf3c92487ca 368 }
idinor 0:dcf3c92487ca 369 break;
idinor 0:dcf3c92487ca 370
idinor 0:dcf3c92487ca 371 default:
idinor 0:dcf3c92487ca 372 FSMDEBUG(LOG_INFO, ("%s: UNHANDLED timeout event in state %d (%s)!\n",
idinor 0:dcf3c92487ca 373 PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
idinor 0:dcf3c92487ca 374 }
idinor 0:dcf3c92487ca 375 }
idinor 0:dcf3c92487ca 376
idinor 0:dcf3c92487ca 377
idinor 0:dcf3c92487ca 378 /*
idinor 0:dcf3c92487ca 379 * fsm_input - Input packet.
idinor 0:dcf3c92487ca 380 */
idinor 0:dcf3c92487ca 381 void
idinor 0:dcf3c92487ca 382 fsm_input(fsm *f, u_char *inpacket, int l)
idinor 0:dcf3c92487ca 383 {
idinor 0:dcf3c92487ca 384 u_char *inp = inpacket;
idinor 0:dcf3c92487ca 385 u_char code, id;
idinor 0:dcf3c92487ca 386 int len;
idinor 0:dcf3c92487ca 387
idinor 0:dcf3c92487ca 388 /*
idinor 0:dcf3c92487ca 389 * Parse header (code, id and length).
idinor 0:dcf3c92487ca 390 * If packet too short, drop it.
idinor 0:dcf3c92487ca 391 */
idinor 0:dcf3c92487ca 392 if (l < HEADERLEN) {
idinor 0:dcf3c92487ca 393 FSMDEBUG(LOG_WARNING, ("fsm_input(%x): Rcvd short header.\n",
idinor 0:dcf3c92487ca 394 f->protocol));
idinor 0:dcf3c92487ca 395 return;
idinor 0:dcf3c92487ca 396 }
idinor 0:dcf3c92487ca 397 GETCHAR(code, inp);
idinor 0:dcf3c92487ca 398 GETCHAR(id, inp);
idinor 0:dcf3c92487ca 399 GETSHORT(len, inp);
idinor 0:dcf3c92487ca 400 if (len < HEADERLEN) {
idinor 0:dcf3c92487ca 401 FSMDEBUG(LOG_INFO, ("fsm_input(%x): Rcvd illegal length.\n",
idinor 0:dcf3c92487ca 402 f->protocol));
idinor 0:dcf3c92487ca 403 return;
idinor 0:dcf3c92487ca 404 }
idinor 0:dcf3c92487ca 405 if (len > l) {
idinor 0:dcf3c92487ca 406 FSMDEBUG(LOG_INFO, ("fsm_input(%x): Rcvd short packet.\n",
idinor 0:dcf3c92487ca 407 f->protocol));
idinor 0:dcf3c92487ca 408 return;
idinor 0:dcf3c92487ca 409 }
idinor 0:dcf3c92487ca 410 len -= HEADERLEN; /* subtract header length */
idinor 0:dcf3c92487ca 411
idinor 0:dcf3c92487ca 412 if( f->state == LS_INITIAL || f->state == LS_STARTING ) {
idinor 0:dcf3c92487ca 413 FSMDEBUG(LOG_INFO, ("fsm_input(%x): Rcvd packet in state %d (%s).\n",
idinor 0:dcf3c92487ca 414 f->protocol, f->state, ppperr_strerr[f->state]));
idinor 0:dcf3c92487ca 415 return;
idinor 0:dcf3c92487ca 416 }
idinor 0:dcf3c92487ca 417 FSMDEBUG(LOG_INFO, ("fsm_input(%s):%d,%d,%d\n", PROTO_NAME(f), code, id, l));
idinor 0:dcf3c92487ca 418 /*
idinor 0:dcf3c92487ca 419 * Action depends on code.
idinor 0:dcf3c92487ca 420 */
idinor 0:dcf3c92487ca 421 switch (code) {
idinor 0:dcf3c92487ca 422 case CONFREQ:
idinor 0:dcf3c92487ca 423 fsm_rconfreq(f, id, inp, len);
idinor 0:dcf3c92487ca 424 break;
idinor 0:dcf3c92487ca 425
idinor 0:dcf3c92487ca 426 case CONFACK:
idinor 0:dcf3c92487ca 427 fsm_rconfack(f, id, inp, len);
idinor 0:dcf3c92487ca 428 break;
idinor 0:dcf3c92487ca 429
idinor 0:dcf3c92487ca 430 case CONFNAK:
idinor 0:dcf3c92487ca 431 case CONFREJ:
idinor 0:dcf3c92487ca 432 fsm_rconfnakrej(f, code, id, inp, len);
idinor 0:dcf3c92487ca 433 break;
idinor 0:dcf3c92487ca 434
idinor 0:dcf3c92487ca 435 case TERMREQ:
idinor 0:dcf3c92487ca 436 fsm_rtermreq(f, id, inp, len);
idinor 0:dcf3c92487ca 437 break;
idinor 0:dcf3c92487ca 438
idinor 0:dcf3c92487ca 439 case TERMACK:
idinor 0:dcf3c92487ca 440 fsm_rtermack(f);
idinor 0:dcf3c92487ca 441 break;
idinor 0:dcf3c92487ca 442
idinor 0:dcf3c92487ca 443 case CODEREJ:
idinor 0:dcf3c92487ca 444 fsm_rcoderej(f, inp, len);
idinor 0:dcf3c92487ca 445 break;
idinor 0:dcf3c92487ca 446
idinor 0:dcf3c92487ca 447 default:
idinor 0:dcf3c92487ca 448 FSMDEBUG(LOG_INFO, ("fsm_input(%s): default: \n", PROTO_NAME(f)));
idinor 0:dcf3c92487ca 449 if( !f->callbacks->extcode ||
idinor 0:dcf3c92487ca 450 !(*f->callbacks->extcode)(f, code, id, inp, len) ) {
idinor 0:dcf3c92487ca 451 fsm_sdata(f, CODEREJ, ++f->id, inpacket, len + HEADERLEN);
idinor 0:dcf3c92487ca 452 }
idinor 0:dcf3c92487ca 453 break;
idinor 0:dcf3c92487ca 454 }
idinor 0:dcf3c92487ca 455 }
idinor 0:dcf3c92487ca 456
idinor 0:dcf3c92487ca 457
idinor 0:dcf3c92487ca 458 /*
idinor 0:dcf3c92487ca 459 * fsm_rconfreq - Receive Configure-Request.
idinor 0:dcf3c92487ca 460 */
idinor 0:dcf3c92487ca 461 static void
idinor 0:dcf3c92487ca 462 fsm_rconfreq(fsm *f, u_char id, u_char *inp, int len)
idinor 0:dcf3c92487ca 463 {
idinor 0:dcf3c92487ca 464 int code, reject_if_disagree;
idinor 0:dcf3c92487ca 465
idinor 0:dcf3c92487ca 466 FSMDEBUG(LOG_INFO, ("fsm_rconfreq(%s): Rcvd id %d state=%d (%s)\n",
idinor 0:dcf3c92487ca 467 PROTO_NAME(f), id, f->state, ppperr_strerr[f->state]));
idinor 0:dcf3c92487ca 468 switch( f->state ) {
idinor 0:dcf3c92487ca 469 case LS_CLOSED:
idinor 0:dcf3c92487ca 470 /* Go away, we're closed */
idinor 0:dcf3c92487ca 471 fsm_sdata(f, TERMACK, id, NULL, 0);
idinor 0:dcf3c92487ca 472 return;
idinor 0:dcf3c92487ca 473 case LS_CLOSING:
idinor 0:dcf3c92487ca 474 case LS_STOPPING:
idinor 0:dcf3c92487ca 475 return;
idinor 0:dcf3c92487ca 476
idinor 0:dcf3c92487ca 477 case LS_OPENED:
idinor 0:dcf3c92487ca 478 /* Go down and restart negotiation */
idinor 0:dcf3c92487ca 479 if( f->callbacks->down ) {
idinor 0:dcf3c92487ca 480 (*f->callbacks->down)(f); /* Inform upper layers */
idinor 0:dcf3c92487ca 481 }
idinor 0:dcf3c92487ca 482 fsm_sconfreq(f, 0); /* Send initial Configure-Request */
idinor 0:dcf3c92487ca 483 break;
idinor 0:dcf3c92487ca 484
idinor 0:dcf3c92487ca 485 case LS_STOPPED:
idinor 0:dcf3c92487ca 486 /* Negotiation started by our peer */
idinor 0:dcf3c92487ca 487 fsm_sconfreq(f, 0); /* Send initial Configure-Request */
idinor 0:dcf3c92487ca 488 f->state = LS_REQSENT;
idinor 0:dcf3c92487ca 489 break;
idinor 0:dcf3c92487ca 490 }
idinor 0:dcf3c92487ca 491
idinor 0:dcf3c92487ca 492 /*
idinor 0:dcf3c92487ca 493 * Pass the requested configuration options
idinor 0:dcf3c92487ca 494 * to protocol-specific code for checking.
idinor 0:dcf3c92487ca 495 */
idinor 0:dcf3c92487ca 496 if (f->callbacks->reqci) { /* Check CI */
idinor 0:dcf3c92487ca 497 reject_if_disagree = (f->nakloops >= f->maxnakloops);
idinor 0:dcf3c92487ca 498 code = (*f->callbacks->reqci)(f, inp, &len, reject_if_disagree);
idinor 0:dcf3c92487ca 499 } else if (len) {
idinor 0:dcf3c92487ca 500 code = CONFREJ; /* Reject all CI */
idinor 0:dcf3c92487ca 501 } else {
idinor 0:dcf3c92487ca 502 code = CONFACK;
idinor 0:dcf3c92487ca 503 }
idinor 0:dcf3c92487ca 504
idinor 0:dcf3c92487ca 505 /* send the Ack, Nak or Rej to the peer */
idinor 0:dcf3c92487ca 506 fsm_sdata(f, (u_char)code, id, inp, len);
idinor 0:dcf3c92487ca 507
idinor 0:dcf3c92487ca 508 if (code == CONFACK) {
idinor 0:dcf3c92487ca 509 if (f->state == LS_ACKRCVD) {
idinor 0:dcf3c92487ca 510 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
idinor 0:dcf3c92487ca 511 f->state = LS_OPENED;
idinor 0:dcf3c92487ca 512 if (f->callbacks->up) {
idinor 0:dcf3c92487ca 513 (*f->callbacks->up)(f); /* Inform upper layers */
idinor 0:dcf3c92487ca 514 }
idinor 0:dcf3c92487ca 515 } else {
idinor 0:dcf3c92487ca 516 f->state = LS_ACKSENT;
idinor 0:dcf3c92487ca 517 }
idinor 0:dcf3c92487ca 518 f->nakloops = 0;
idinor 0:dcf3c92487ca 519 } else {
idinor 0:dcf3c92487ca 520 /* we sent CONFACK or CONFREJ */
idinor 0:dcf3c92487ca 521 if (f->state != LS_ACKRCVD) {
idinor 0:dcf3c92487ca 522 f->state = LS_REQSENT;
idinor 0:dcf3c92487ca 523 }
idinor 0:dcf3c92487ca 524 if( code == CONFNAK ) {
idinor 0:dcf3c92487ca 525 ++f->nakloops;
idinor 0:dcf3c92487ca 526 }
idinor 0:dcf3c92487ca 527 }
idinor 0:dcf3c92487ca 528 }
idinor 0:dcf3c92487ca 529
idinor 0:dcf3c92487ca 530
idinor 0:dcf3c92487ca 531 /*
idinor 0:dcf3c92487ca 532 * fsm_rconfack - Receive Configure-Ack.
idinor 0:dcf3c92487ca 533 */
idinor 0:dcf3c92487ca 534 static void
idinor 0:dcf3c92487ca 535 fsm_rconfack(fsm *f, int id, u_char *inp, int len)
idinor 0:dcf3c92487ca 536 {
idinor 0:dcf3c92487ca 537 FSMDEBUG(LOG_INFO, ("fsm_rconfack(%s): Rcvd id %d state=%d (%s)\n",
idinor 0:dcf3c92487ca 538 PROTO_NAME(f), id, f->state, ppperr_strerr[f->state]));
idinor 0:dcf3c92487ca 539
idinor 0:dcf3c92487ca 540 if (id != f->reqid || f->seen_ack) { /* Expected id? */
idinor 0:dcf3c92487ca 541 return; /* Nope, toss... */
idinor 0:dcf3c92487ca 542 }
idinor 0:dcf3c92487ca 543 if( !(f->callbacks->ackci? (*f->callbacks->ackci)(f, inp, len): (len == 0)) ) {
idinor 0:dcf3c92487ca 544 /* Ack is bad - ignore it */
idinor 0:dcf3c92487ca 545 FSMDEBUG(LOG_INFO, ("%s: received bad Ack (length %d)\n",
idinor 0:dcf3c92487ca 546 PROTO_NAME(f), len));
idinor 0:dcf3c92487ca 547 return;
idinor 0:dcf3c92487ca 548 }
idinor 0:dcf3c92487ca 549 f->seen_ack = 1;
idinor 0:dcf3c92487ca 550
idinor 0:dcf3c92487ca 551 switch (f->state) {
idinor 0:dcf3c92487ca 552 case LS_CLOSED:
idinor 0:dcf3c92487ca 553 case LS_STOPPED:
idinor 0:dcf3c92487ca 554 fsm_sdata(f, TERMACK, (u_char)id, NULL, 0);
idinor 0:dcf3c92487ca 555 break;
idinor 0:dcf3c92487ca 556
idinor 0:dcf3c92487ca 557 case LS_REQSENT:
idinor 0:dcf3c92487ca 558 f->state = LS_ACKRCVD;
idinor 0:dcf3c92487ca 559 f->retransmits = f->maxconfreqtransmits;
idinor 0:dcf3c92487ca 560 break;
idinor 0:dcf3c92487ca 561
idinor 0:dcf3c92487ca 562 case LS_ACKRCVD:
idinor 0:dcf3c92487ca 563 /* Huh? an extra valid Ack? oh well... */
idinor 0:dcf3c92487ca 564 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
idinor 0:dcf3c92487ca 565 fsm_sconfreq(f, 0);
idinor 0:dcf3c92487ca 566 f->state = LS_REQSENT;
idinor 0:dcf3c92487ca 567 break;
idinor 0:dcf3c92487ca 568
idinor 0:dcf3c92487ca 569 case LS_ACKSENT:
idinor 0:dcf3c92487ca 570 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
idinor 0:dcf3c92487ca 571 f->state = LS_OPENED;
idinor 0:dcf3c92487ca 572 f->retransmits = f->maxconfreqtransmits;
idinor 0:dcf3c92487ca 573 if (f->callbacks->up) {
idinor 0:dcf3c92487ca 574 (*f->callbacks->up)(f); /* Inform upper layers */
idinor 0:dcf3c92487ca 575 }
idinor 0:dcf3c92487ca 576 break;
idinor 0:dcf3c92487ca 577
idinor 0:dcf3c92487ca 578 case LS_OPENED:
idinor 0:dcf3c92487ca 579 /* Go down and restart negotiation */
idinor 0:dcf3c92487ca 580 if (f->callbacks->down) {
idinor 0:dcf3c92487ca 581 (*f->callbacks->down)(f); /* Inform upper layers */
idinor 0:dcf3c92487ca 582 }
idinor 0:dcf3c92487ca 583 fsm_sconfreq(f, 0); /* Send initial Configure-Request */
idinor 0:dcf3c92487ca 584 f->state = LS_REQSENT;
idinor 0:dcf3c92487ca 585 break;
idinor 0:dcf3c92487ca 586 }
idinor 0:dcf3c92487ca 587 }
idinor 0:dcf3c92487ca 588
idinor 0:dcf3c92487ca 589
idinor 0:dcf3c92487ca 590 /*
idinor 0:dcf3c92487ca 591 * fsm_rconfnakrej - Receive Configure-Nak or Configure-Reject.
idinor 0:dcf3c92487ca 592 */
idinor 0:dcf3c92487ca 593 static void
idinor 0:dcf3c92487ca 594 fsm_rconfnakrej(fsm *f, int code, int id, u_char *inp, int len)
idinor 0:dcf3c92487ca 595 {
idinor 0:dcf3c92487ca 596 int (*proc) (fsm *, u_char *, int);
idinor 0:dcf3c92487ca 597 int ret;
idinor 0:dcf3c92487ca 598
idinor 0:dcf3c92487ca 599 FSMDEBUG(LOG_INFO, ("fsm_rconfnakrej(%s): Rcvd id %d state=%d (%s)\n",
idinor 0:dcf3c92487ca 600 PROTO_NAME(f), id, f->state, ppperr_strerr[f->state]));
idinor 0:dcf3c92487ca 601
idinor 0:dcf3c92487ca 602 if (id != f->reqid || f->seen_ack) { /* Expected id? */
idinor 0:dcf3c92487ca 603 return; /* Nope, toss... */
idinor 0:dcf3c92487ca 604 }
idinor 0:dcf3c92487ca 605 proc = (code == CONFNAK)? f->callbacks->nakci: f->callbacks->rejci;
idinor 0:dcf3c92487ca 606 if (!proc || !((ret = proc(f, inp, len)))) {
idinor 0:dcf3c92487ca 607 /* Nak/reject is bad - ignore it */
idinor 0:dcf3c92487ca 608 FSMDEBUG(LOG_INFO, ("%s: received bad %s (length %d)\n",
idinor 0:dcf3c92487ca 609 PROTO_NAME(f), (code==CONFNAK? "Nak": "reject"), len));
idinor 0:dcf3c92487ca 610 return;
idinor 0:dcf3c92487ca 611 }
idinor 0:dcf3c92487ca 612 f->seen_ack = 1;
idinor 0:dcf3c92487ca 613
idinor 0:dcf3c92487ca 614 switch (f->state) {
idinor 0:dcf3c92487ca 615 case LS_CLOSED:
idinor 0:dcf3c92487ca 616 case LS_STOPPED:
idinor 0:dcf3c92487ca 617 fsm_sdata(f, TERMACK, (u_char)id, NULL, 0);
idinor 0:dcf3c92487ca 618 break;
idinor 0:dcf3c92487ca 619
idinor 0:dcf3c92487ca 620 case LS_REQSENT:
idinor 0:dcf3c92487ca 621 case LS_ACKSENT:
idinor 0:dcf3c92487ca 622 /* They didn't agree to what we wanted - try another request */
idinor 0:dcf3c92487ca 623 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
idinor 0:dcf3c92487ca 624 if (ret < 0) {
idinor 0:dcf3c92487ca 625 f->state = LS_STOPPED; /* kludge for stopping CCP */
idinor 0:dcf3c92487ca 626 } else {
idinor 0:dcf3c92487ca 627 fsm_sconfreq(f, 0); /* Send Configure-Request */
idinor 0:dcf3c92487ca 628 }
idinor 0:dcf3c92487ca 629 break;
idinor 0:dcf3c92487ca 630
idinor 0:dcf3c92487ca 631 case LS_ACKRCVD:
idinor 0:dcf3c92487ca 632 /* Got a Nak/reject when we had already had an Ack?? oh well... */
idinor 0:dcf3c92487ca 633 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
idinor 0:dcf3c92487ca 634 fsm_sconfreq(f, 0);
idinor 0:dcf3c92487ca 635 f->state = LS_REQSENT;
idinor 0:dcf3c92487ca 636 break;
idinor 0:dcf3c92487ca 637
idinor 0:dcf3c92487ca 638 case LS_OPENED:
idinor 0:dcf3c92487ca 639 /* Go down and restart negotiation */
idinor 0:dcf3c92487ca 640 if (f->callbacks->down) {
idinor 0:dcf3c92487ca 641 (*f->callbacks->down)(f); /* Inform upper layers */
idinor 0:dcf3c92487ca 642 }
idinor 0:dcf3c92487ca 643 fsm_sconfreq(f, 0); /* Send initial Configure-Request */
idinor 0:dcf3c92487ca 644 f->state = LS_REQSENT;
idinor 0:dcf3c92487ca 645 break;
idinor 0:dcf3c92487ca 646 }
idinor 0:dcf3c92487ca 647 }
idinor 0:dcf3c92487ca 648
idinor 0:dcf3c92487ca 649
idinor 0:dcf3c92487ca 650 /*
idinor 0:dcf3c92487ca 651 * fsm_rtermreq - Receive Terminate-Req.
idinor 0:dcf3c92487ca 652 */
idinor 0:dcf3c92487ca 653 static void
idinor 0:dcf3c92487ca 654 fsm_rtermreq(fsm *f, int id, u_char *p, int len)
idinor 0:dcf3c92487ca 655 {
idinor 0:dcf3c92487ca 656 LWIP_UNUSED_ARG(p);
idinor 0:dcf3c92487ca 657
idinor 0:dcf3c92487ca 658 FSMDEBUG(LOG_INFO, ("fsm_rtermreq(%s): Rcvd id %d state=%d (%s)\n",
idinor 0:dcf3c92487ca 659 PROTO_NAME(f), id, f->state, ppperr_strerr[f->state]));
idinor 0:dcf3c92487ca 660
idinor 0:dcf3c92487ca 661 switch (f->state) {
idinor 0:dcf3c92487ca 662 case LS_ACKRCVD:
idinor 0:dcf3c92487ca 663 case LS_ACKSENT:
idinor 0:dcf3c92487ca 664 f->state = LS_REQSENT; /* Start over but keep trying */
idinor 0:dcf3c92487ca 665 break;
idinor 0:dcf3c92487ca 666
idinor 0:dcf3c92487ca 667 case LS_OPENED:
idinor 0:dcf3c92487ca 668 if (len > 0) {
idinor 0:dcf3c92487ca 669 FSMDEBUG(LOG_INFO, ("%s terminated by peer (%p)\n", PROTO_NAME(f), p));
idinor 0:dcf3c92487ca 670 } else {
idinor 0:dcf3c92487ca 671 FSMDEBUG(LOG_INFO, ("%s terminated by peer\n", PROTO_NAME(f)));
idinor 0:dcf3c92487ca 672 }
idinor 0:dcf3c92487ca 673 if (f->callbacks->down) {
idinor 0:dcf3c92487ca 674 (*f->callbacks->down)(f); /* Inform upper layers */
idinor 0:dcf3c92487ca 675 }
idinor 0:dcf3c92487ca 676 f->retransmits = 0;
idinor 0:dcf3c92487ca 677 f->state = LS_STOPPING;
idinor 0:dcf3c92487ca 678 TIMEOUT(fsm_timeout, f, f->timeouttime);
idinor 0:dcf3c92487ca 679 break;
idinor 0:dcf3c92487ca 680 }
idinor 0:dcf3c92487ca 681
idinor 0:dcf3c92487ca 682 fsm_sdata(f, TERMACK, (u_char)id, NULL, 0);
idinor 0:dcf3c92487ca 683 }
idinor 0:dcf3c92487ca 684
idinor 0:dcf3c92487ca 685
idinor 0:dcf3c92487ca 686 /*
idinor 0:dcf3c92487ca 687 * fsm_rtermack - Receive Terminate-Ack.
idinor 0:dcf3c92487ca 688 */
idinor 0:dcf3c92487ca 689 static void
idinor 0:dcf3c92487ca 690 fsm_rtermack(fsm *f)
idinor 0:dcf3c92487ca 691 {
idinor 0:dcf3c92487ca 692 FSMDEBUG(LOG_INFO, ("fsm_rtermack(%s): state=%d (%s)\n",
idinor 0:dcf3c92487ca 693 PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
idinor 0:dcf3c92487ca 694
idinor 0:dcf3c92487ca 695 switch (f->state) {
idinor 0:dcf3c92487ca 696 case LS_CLOSING:
idinor 0:dcf3c92487ca 697 UNTIMEOUT(fsm_timeout, f);
idinor 0:dcf3c92487ca 698 f->state = LS_CLOSED;
idinor 0:dcf3c92487ca 699 if( f->callbacks->finished ) {
idinor 0:dcf3c92487ca 700 (*f->callbacks->finished)(f);
idinor 0:dcf3c92487ca 701 }
idinor 0:dcf3c92487ca 702 break;
idinor 0:dcf3c92487ca 703
idinor 0:dcf3c92487ca 704 case LS_STOPPING:
idinor 0:dcf3c92487ca 705 UNTIMEOUT(fsm_timeout, f);
idinor 0:dcf3c92487ca 706 f->state = LS_STOPPED;
idinor 0:dcf3c92487ca 707 if( f->callbacks->finished ) {
idinor 0:dcf3c92487ca 708 (*f->callbacks->finished)(f);
idinor 0:dcf3c92487ca 709 }
idinor 0:dcf3c92487ca 710 break;
idinor 0:dcf3c92487ca 711
idinor 0:dcf3c92487ca 712 case LS_ACKRCVD:
idinor 0:dcf3c92487ca 713 f->state = LS_REQSENT;
idinor 0:dcf3c92487ca 714 break;
idinor 0:dcf3c92487ca 715
idinor 0:dcf3c92487ca 716 case LS_OPENED:
idinor 0:dcf3c92487ca 717 if (f->callbacks->down) {
idinor 0:dcf3c92487ca 718 (*f->callbacks->down)(f); /* Inform upper layers */
idinor 0:dcf3c92487ca 719 }
idinor 0:dcf3c92487ca 720 fsm_sconfreq(f, 0);
idinor 0:dcf3c92487ca 721 break;
idinor 0:dcf3c92487ca 722 default:
idinor 0:dcf3c92487ca 723 FSMDEBUG(LOG_INFO, ("fsm_rtermack(%s): UNHANDLED state=%d (%s)!!!\n",
idinor 0:dcf3c92487ca 724 PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
idinor 0:dcf3c92487ca 725 }
idinor 0:dcf3c92487ca 726 }
idinor 0:dcf3c92487ca 727
idinor 0:dcf3c92487ca 728
idinor 0:dcf3c92487ca 729 /*
idinor 0:dcf3c92487ca 730 * fsm_rcoderej - Receive an Code-Reject.
idinor 0:dcf3c92487ca 731 */
idinor 0:dcf3c92487ca 732 static void
idinor 0:dcf3c92487ca 733 fsm_rcoderej(fsm *f, u_char *inp, int len)
idinor 0:dcf3c92487ca 734 {
idinor 0:dcf3c92487ca 735 u_char code, id;
idinor 0:dcf3c92487ca 736
idinor 0:dcf3c92487ca 737 FSMDEBUG(LOG_INFO, ("fsm_rcoderej(%s): state=%d (%s)\n",
idinor 0:dcf3c92487ca 738 PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
idinor 0:dcf3c92487ca 739
idinor 0:dcf3c92487ca 740 if (len < HEADERLEN) {
idinor 0:dcf3c92487ca 741 FSMDEBUG(LOG_INFO, ("fsm_rcoderej: Rcvd short Code-Reject packet!\n"));
idinor 0:dcf3c92487ca 742 return;
idinor 0:dcf3c92487ca 743 }
idinor 0:dcf3c92487ca 744 GETCHAR(code, inp);
idinor 0:dcf3c92487ca 745 GETCHAR(id, inp);
idinor 0:dcf3c92487ca 746 FSMDEBUG(LOG_WARNING, ("%s: Rcvd Code-Reject for code %d, id %d\n",
idinor 0:dcf3c92487ca 747 PROTO_NAME(f), code, id));
idinor 0:dcf3c92487ca 748
idinor 0:dcf3c92487ca 749 if( f->state == LS_ACKRCVD ) {
idinor 0:dcf3c92487ca 750 f->state = LS_REQSENT;
idinor 0:dcf3c92487ca 751 }
idinor 0:dcf3c92487ca 752 }
idinor 0:dcf3c92487ca 753
idinor 0:dcf3c92487ca 754
idinor 0:dcf3c92487ca 755 /*
idinor 0:dcf3c92487ca 756 * fsm_protreject - Peer doesn't speak this protocol.
idinor 0:dcf3c92487ca 757 *
idinor 0:dcf3c92487ca 758 * Treat this as a catastrophic error (RXJ-).
idinor 0:dcf3c92487ca 759 */
idinor 0:dcf3c92487ca 760 void
idinor 0:dcf3c92487ca 761 fsm_protreject(fsm *f)
idinor 0:dcf3c92487ca 762 {
idinor 0:dcf3c92487ca 763 switch( f->state ) {
idinor 0:dcf3c92487ca 764 case LS_CLOSING:
idinor 0:dcf3c92487ca 765 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
idinor 0:dcf3c92487ca 766 /* fall through */
idinor 0:dcf3c92487ca 767 case LS_CLOSED:
idinor 0:dcf3c92487ca 768 f->state = LS_CLOSED;
idinor 0:dcf3c92487ca 769 if( f->callbacks->finished ) {
idinor 0:dcf3c92487ca 770 (*f->callbacks->finished)(f);
idinor 0:dcf3c92487ca 771 }
idinor 0:dcf3c92487ca 772 break;
idinor 0:dcf3c92487ca 773
idinor 0:dcf3c92487ca 774 case LS_STOPPING:
idinor 0:dcf3c92487ca 775 case LS_REQSENT:
idinor 0:dcf3c92487ca 776 case LS_ACKRCVD:
idinor 0:dcf3c92487ca 777 case LS_ACKSENT:
idinor 0:dcf3c92487ca 778 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
idinor 0:dcf3c92487ca 779 /* fall through */
idinor 0:dcf3c92487ca 780 case LS_STOPPED:
idinor 0:dcf3c92487ca 781 f->state = LS_STOPPED;
idinor 0:dcf3c92487ca 782 if( f->callbacks->finished ) {
idinor 0:dcf3c92487ca 783 (*f->callbacks->finished)(f);
idinor 0:dcf3c92487ca 784 }
idinor 0:dcf3c92487ca 785 break;
idinor 0:dcf3c92487ca 786
idinor 0:dcf3c92487ca 787 case LS_OPENED:
idinor 0:dcf3c92487ca 788 if( f->callbacks->down ) {
idinor 0:dcf3c92487ca 789 (*f->callbacks->down)(f);
idinor 0:dcf3c92487ca 790 }
idinor 0:dcf3c92487ca 791 /* Init restart counter, send Terminate-Request */
idinor 0:dcf3c92487ca 792 f->retransmits = f->maxtermtransmits;
idinor 0:dcf3c92487ca 793 fsm_sdata(f, TERMREQ, f->reqid = ++f->id,
idinor 0:dcf3c92487ca 794 (u_char *) f->term_reason, f->term_reason_len);
idinor 0:dcf3c92487ca 795 TIMEOUT(fsm_timeout, f, f->timeouttime);
idinor 0:dcf3c92487ca 796 --f->retransmits;
idinor 0:dcf3c92487ca 797
idinor 0:dcf3c92487ca 798 f->state = LS_STOPPING;
idinor 0:dcf3c92487ca 799 break;
idinor 0:dcf3c92487ca 800
idinor 0:dcf3c92487ca 801 default:
idinor 0:dcf3c92487ca 802 FSMDEBUG(LOG_INFO, ("%s: Protocol-reject event in state %d (%s)!\n",
idinor 0:dcf3c92487ca 803 PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
idinor 0:dcf3c92487ca 804 }
idinor 0:dcf3c92487ca 805 }
idinor 0:dcf3c92487ca 806
idinor 0:dcf3c92487ca 807
idinor 0:dcf3c92487ca 808 /*
idinor 0:dcf3c92487ca 809 * fsm_sconfreq - Send a Configure-Request.
idinor 0:dcf3c92487ca 810 */
idinor 0:dcf3c92487ca 811 static void
idinor 0:dcf3c92487ca 812 fsm_sconfreq(fsm *f, int retransmit)
idinor 0:dcf3c92487ca 813 {
idinor 0:dcf3c92487ca 814 u_char *outp;
idinor 0:dcf3c92487ca 815 int cilen;
idinor 0:dcf3c92487ca 816
idinor 0:dcf3c92487ca 817 if( f->state != LS_REQSENT && f->state != LS_ACKRCVD && f->state != LS_ACKSENT ) {
idinor 0:dcf3c92487ca 818 /* Not currently negotiating - reset options */
idinor 0:dcf3c92487ca 819 if( f->callbacks->resetci ) {
idinor 0:dcf3c92487ca 820 (*f->callbacks->resetci)(f);
idinor 0:dcf3c92487ca 821 }
idinor 0:dcf3c92487ca 822 f->nakloops = 0;
idinor 0:dcf3c92487ca 823 }
idinor 0:dcf3c92487ca 824
idinor 0:dcf3c92487ca 825 if( !retransmit ) {
idinor 0:dcf3c92487ca 826 /* New request - reset retransmission counter, use new ID */
idinor 0:dcf3c92487ca 827 f->retransmits = f->maxconfreqtransmits;
idinor 0:dcf3c92487ca 828 f->reqid = ++f->id;
idinor 0:dcf3c92487ca 829 }
idinor 0:dcf3c92487ca 830
idinor 0:dcf3c92487ca 831 f->seen_ack = 0;
idinor 0:dcf3c92487ca 832
idinor 0:dcf3c92487ca 833 /*
idinor 0:dcf3c92487ca 834 * Make up the request packet
idinor 0:dcf3c92487ca 835 */
idinor 0:dcf3c92487ca 836 outp = outpacket_buf[f->unit] + PPP_HDRLEN + HEADERLEN;
idinor 0:dcf3c92487ca 837 if( f->callbacks->cilen && f->callbacks->addci ) {
idinor 0:dcf3c92487ca 838 cilen = (*f->callbacks->cilen)(f);
idinor 0:dcf3c92487ca 839 if( cilen > peer_mru[f->unit] - (int)HEADERLEN ) {
idinor 0:dcf3c92487ca 840 cilen = peer_mru[f->unit] - HEADERLEN;
idinor 0:dcf3c92487ca 841 }
idinor 0:dcf3c92487ca 842 if (f->callbacks->addci) {
idinor 0:dcf3c92487ca 843 (*f->callbacks->addci)(f, outp, &cilen);
idinor 0:dcf3c92487ca 844 }
idinor 0:dcf3c92487ca 845 } else {
idinor 0:dcf3c92487ca 846 cilen = 0;
idinor 0:dcf3c92487ca 847 }
idinor 0:dcf3c92487ca 848
idinor 0:dcf3c92487ca 849 /* send the request to our peer */
idinor 0:dcf3c92487ca 850 fsm_sdata(f, CONFREQ, f->reqid, outp, cilen);
idinor 0:dcf3c92487ca 851
idinor 0:dcf3c92487ca 852 /* start the retransmit timer */
idinor 0:dcf3c92487ca 853 --f->retransmits;
idinor 0:dcf3c92487ca 854 TIMEOUT(fsm_timeout, f, f->timeouttime);
idinor 0:dcf3c92487ca 855
idinor 0:dcf3c92487ca 856 FSMDEBUG(LOG_INFO, ("%s: sending Configure-Request, id %d\n",
idinor 0:dcf3c92487ca 857 PROTO_NAME(f), f->reqid));
idinor 0:dcf3c92487ca 858 }
idinor 0:dcf3c92487ca 859
idinor 0:dcf3c92487ca 860
idinor 0:dcf3c92487ca 861 /*
idinor 0:dcf3c92487ca 862 * fsm_sdata - Send some data.
idinor 0:dcf3c92487ca 863 *
idinor 0:dcf3c92487ca 864 * Used for all packets sent to our peer by this module.
idinor 0:dcf3c92487ca 865 */
idinor 0:dcf3c92487ca 866 void
idinor 0:dcf3c92487ca 867 fsm_sdata( fsm *f, u_char code, u_char id, u_char *data, int datalen)
idinor 0:dcf3c92487ca 868 {
idinor 0:dcf3c92487ca 869 u_char *outp;
idinor 0:dcf3c92487ca 870 int outlen;
idinor 0:dcf3c92487ca 871
idinor 0:dcf3c92487ca 872 /* Adjust length to be smaller than MTU */
idinor 0:dcf3c92487ca 873 outp = outpacket_buf[f->unit];
idinor 0:dcf3c92487ca 874 if (datalen > peer_mru[f->unit] - (int)HEADERLEN) {
idinor 0:dcf3c92487ca 875 datalen = peer_mru[f->unit] - HEADERLEN;
idinor 0:dcf3c92487ca 876 }
idinor 0:dcf3c92487ca 877 if (datalen && data != outp + PPP_HDRLEN + HEADERLEN) {
idinor 0:dcf3c92487ca 878 BCOPY(data, outp + PPP_HDRLEN + HEADERLEN, datalen);
idinor 0:dcf3c92487ca 879 }
idinor 0:dcf3c92487ca 880 outlen = datalen + HEADERLEN;
idinor 0:dcf3c92487ca 881 MAKEHEADER(outp, f->protocol);
idinor 0:dcf3c92487ca 882 PUTCHAR(code, outp);
idinor 0:dcf3c92487ca 883 PUTCHAR(id, outp);
idinor 0:dcf3c92487ca 884 PUTSHORT(outlen, outp);
idinor 0:dcf3c92487ca 885 pppWrite(f->unit, outpacket_buf[f->unit], outlen + PPP_HDRLEN);
idinor 0:dcf3c92487ca 886 FSMDEBUG(LOG_INFO, ("fsm_sdata(%s): Sent code %d,%d,%d.\n",
idinor 0:dcf3c92487ca 887 PROTO_NAME(f), code, id, outlen));
idinor 0:dcf3c92487ca 888 }
idinor 0:dcf3c92487ca 889
idinor 0:dcf3c92487ca 890 #endif /* PPP_SUPPORT */