Dependencies:   mbed

Committer:
dirkx
Date:
Sat Aug 14 15:54:31 2010 +0000
Revision:
5:8e53abda9900
Parent:
0:355018f44c9f

        

Who changed what in which revision?

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