Onenet

Dependents:   K64F_eCompass_OneNET_JW

Committer:
robert_jw
Date:
Mon Jun 20 01:40:20 2016 +0000
Revision:
0:b2805b6888dc
ADS

Who changed what in which revision?

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