Igor Skochinsky / NetServicesSource
Committer:
igorsk
Date:
Wed Jun 29 16:01:58 2011 +0000
Revision:
0:b56b6a05cad4

        

Who changed what in which revision?

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