1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * fsm.c - {Link, IP} Control Protocol Finite State Machine. 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 5*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 6*7c478bd9Sstevel@tonic-gate * 7*7c478bd9Sstevel@tonic-gate * Copyright (c) 1989 Carnegie Mellon University. 8*7c478bd9Sstevel@tonic-gate * All rights reserved. 9*7c478bd9Sstevel@tonic-gate * 10*7c478bd9Sstevel@tonic-gate * Redistribution and use in source and binary forms are permitted 11*7c478bd9Sstevel@tonic-gate * provided that the above copyright notice and this paragraph are 12*7c478bd9Sstevel@tonic-gate * duplicated in all such forms and that any documentation, 13*7c478bd9Sstevel@tonic-gate * advertising materials, and other materials related to such 14*7c478bd9Sstevel@tonic-gate * distribution and use acknowledge that the software was developed 15*7c478bd9Sstevel@tonic-gate * by Carnegie Mellon University. The name of the 16*7c478bd9Sstevel@tonic-gate * University may not be used to endorse or promote products derived 17*7c478bd9Sstevel@tonic-gate * from this software without specific prior written permission. 18*7c478bd9Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 19*7c478bd9Sstevel@tonic-gate * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 20*7c478bd9Sstevel@tonic-gate * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate 23*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 24*7c478bd9Sstevel@tonic-gate #define RCSID "$Id: fsm.c,v 1.17 1999/08/13 06:46:12 paulus Exp $" 25*7c478bd9Sstevel@tonic-gate 26*7c478bd9Sstevel@tonic-gate /* 27*7c478bd9Sstevel@tonic-gate * TODO: 28*7c478bd9Sstevel@tonic-gate * Randomize fsm id on link/init. 29*7c478bd9Sstevel@tonic-gate * Deal with variable outgoing MTU. 30*7c478bd9Sstevel@tonic-gate */ 31*7c478bd9Sstevel@tonic-gate 32*7c478bd9Sstevel@tonic-gate #include <stdio.h> 33*7c478bd9Sstevel@tonic-gate #include <string.h> 34*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 35*7c478bd9Sstevel@tonic-gate #ifndef NO_DRAND48 36*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 37*7c478bd9Sstevel@tonic-gate #endif /* NO_DRAND48 */ 38*7c478bd9Sstevel@tonic-gate 39*7c478bd9Sstevel@tonic-gate #include "pppd.h" 40*7c478bd9Sstevel@tonic-gate #include "fsm.h" 41*7c478bd9Sstevel@tonic-gate 42*7c478bd9Sstevel@tonic-gate #if !defined(lint) && !defined(_lint) 43*7c478bd9Sstevel@tonic-gate static const char rcsid[] = RCSID; 44*7c478bd9Sstevel@tonic-gate #endif 45*7c478bd9Sstevel@tonic-gate 46*7c478bd9Sstevel@tonic-gate static void fsm_timeout __P((void *)); 47*7c478bd9Sstevel@tonic-gate static void fsm_rconfreq __P((fsm *, int, u_char *, int)); 48*7c478bd9Sstevel@tonic-gate static void fsm_rconfack __P((fsm *, int, u_char *, int)); 49*7c478bd9Sstevel@tonic-gate static void fsm_rconfnakrej __P((fsm *, int, int, u_char *, int)); 50*7c478bd9Sstevel@tonic-gate static void fsm_rtermreq __P((fsm *, int, u_char *, int)); 51*7c478bd9Sstevel@tonic-gate static void fsm_rtermack __P((fsm *)); 52*7c478bd9Sstevel@tonic-gate static void fsm_rcoderej __P((fsm *, u_char *, int)); 53*7c478bd9Sstevel@tonic-gate static void fsm_sconfreq __P((fsm *, int)); 54*7c478bd9Sstevel@tonic-gate 55*7c478bd9Sstevel@tonic-gate #define PROTO_NAME(f) ((f)->callbacks->proto_name) 56*7c478bd9Sstevel@tonic-gate 57*7c478bd9Sstevel@tonic-gate static int peer_mru[NUM_PPP]; 58*7c478bd9Sstevel@tonic-gate 59*7c478bd9Sstevel@tonic-gate const char * 60*7c478bd9Sstevel@tonic-gate fsm_state(int statenum) 61*7c478bd9Sstevel@tonic-gate { 62*7c478bd9Sstevel@tonic-gate static const char *fsm_states[] = { FSM__STATES }; 63*7c478bd9Sstevel@tonic-gate static char buf[32]; 64*7c478bd9Sstevel@tonic-gate 65*7c478bd9Sstevel@tonic-gate if (statenum < 0 || statenum >= Dim(fsm_states)) { 66*7c478bd9Sstevel@tonic-gate (void) slprintf(buf, sizeof (buf), "unknown#%d", statenum); 67*7c478bd9Sstevel@tonic-gate return buf; 68*7c478bd9Sstevel@tonic-gate } 69*7c478bd9Sstevel@tonic-gate return fsm_states[statenum]; 70*7c478bd9Sstevel@tonic-gate } 71*7c478bd9Sstevel@tonic-gate 72*7c478bd9Sstevel@tonic-gate /* 73*7c478bd9Sstevel@tonic-gate * fsm_init - Initialize fsm. 74*7c478bd9Sstevel@tonic-gate * 75*7c478bd9Sstevel@tonic-gate * Initialize fsm state. 76*7c478bd9Sstevel@tonic-gate */ 77*7c478bd9Sstevel@tonic-gate void 78*7c478bd9Sstevel@tonic-gate fsm_init(f) 79*7c478bd9Sstevel@tonic-gate fsm *f; 80*7c478bd9Sstevel@tonic-gate { 81*7c478bd9Sstevel@tonic-gate f->state = INITIAL; 82*7c478bd9Sstevel@tonic-gate f->flags = 0; 83*7c478bd9Sstevel@tonic-gate f->id = (uchar_t)(drand48() * 0xFF); /* Start with random id */ 84*7c478bd9Sstevel@tonic-gate f->timeouttime = DEFTIMEOUT; 85*7c478bd9Sstevel@tonic-gate f->maxconfreqtransmits = DEFMAXCONFREQS; 86*7c478bd9Sstevel@tonic-gate f->maxtermtransmits = DEFMAXTERMREQS; 87*7c478bd9Sstevel@tonic-gate f->maxnakloops = DEFMAXNAKLOOPS; 88*7c478bd9Sstevel@tonic-gate f->term_reason_len = 0; 89*7c478bd9Sstevel@tonic-gate } 90*7c478bd9Sstevel@tonic-gate 91*7c478bd9Sstevel@tonic-gate 92*7c478bd9Sstevel@tonic-gate /* 93*7c478bd9Sstevel@tonic-gate * fsm_lowerup - The lower layer is up. 94*7c478bd9Sstevel@tonic-gate */ 95*7c478bd9Sstevel@tonic-gate void 96*7c478bd9Sstevel@tonic-gate fsm_lowerup(f) 97*7c478bd9Sstevel@tonic-gate fsm *f; 98*7c478bd9Sstevel@tonic-gate { 99*7c478bd9Sstevel@tonic-gate switch( f->state ){ 100*7c478bd9Sstevel@tonic-gate case INITIAL: 101*7c478bd9Sstevel@tonic-gate f->state = CLOSED; 102*7c478bd9Sstevel@tonic-gate break; 103*7c478bd9Sstevel@tonic-gate 104*7c478bd9Sstevel@tonic-gate case STARTING: 105*7c478bd9Sstevel@tonic-gate if( f->flags & OPT_SILENT ) 106*7c478bd9Sstevel@tonic-gate f->state = STOPPED; 107*7c478bd9Sstevel@tonic-gate else { 108*7c478bd9Sstevel@tonic-gate /* Send an initial configure-request */ 109*7c478bd9Sstevel@tonic-gate fsm_sconfreq(f, 0); 110*7c478bd9Sstevel@tonic-gate f->state = REQSENT; 111*7c478bd9Sstevel@tonic-gate } 112*7c478bd9Sstevel@tonic-gate break; 113*7c478bd9Sstevel@tonic-gate 114*7c478bd9Sstevel@tonic-gate default: 115*7c478bd9Sstevel@tonic-gate error("%s: Up event in state %s", PROTO_NAME(f), fsm_state(f->state)); 116*7c478bd9Sstevel@tonic-gate } 117*7c478bd9Sstevel@tonic-gate } 118*7c478bd9Sstevel@tonic-gate 119*7c478bd9Sstevel@tonic-gate 120*7c478bd9Sstevel@tonic-gate /* 121*7c478bd9Sstevel@tonic-gate * fsm_lowerdown - The lower layer is down. 122*7c478bd9Sstevel@tonic-gate * 123*7c478bd9Sstevel@tonic-gate * Cancel all timeouts and inform upper layers. 124*7c478bd9Sstevel@tonic-gate */ 125*7c478bd9Sstevel@tonic-gate void 126*7c478bd9Sstevel@tonic-gate fsm_lowerdown(f) 127*7c478bd9Sstevel@tonic-gate fsm *f; 128*7c478bd9Sstevel@tonic-gate { 129*7c478bd9Sstevel@tonic-gate switch( f->state ){ 130*7c478bd9Sstevel@tonic-gate case CLOSED: 131*7c478bd9Sstevel@tonic-gate f->state = INITIAL; 132*7c478bd9Sstevel@tonic-gate break; 133*7c478bd9Sstevel@tonic-gate 134*7c478bd9Sstevel@tonic-gate case STOPPED: 135*7c478bd9Sstevel@tonic-gate f->state = STARTING; 136*7c478bd9Sstevel@tonic-gate if (f->callbacks->starting != NULL) 137*7c478bd9Sstevel@tonic-gate (*f->callbacks->starting)(f); 138*7c478bd9Sstevel@tonic-gate break; 139*7c478bd9Sstevel@tonic-gate 140*7c478bd9Sstevel@tonic-gate case CLOSING: 141*7c478bd9Sstevel@tonic-gate f->state = INITIAL; 142*7c478bd9Sstevel@tonic-gate UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ 143*7c478bd9Sstevel@tonic-gate break; 144*7c478bd9Sstevel@tonic-gate 145*7c478bd9Sstevel@tonic-gate case STOPPING: 146*7c478bd9Sstevel@tonic-gate case REQSENT: 147*7c478bd9Sstevel@tonic-gate case ACKRCVD: 148*7c478bd9Sstevel@tonic-gate case ACKSENT: 149*7c478bd9Sstevel@tonic-gate f->state = STARTING; 150*7c478bd9Sstevel@tonic-gate UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ 151*7c478bd9Sstevel@tonic-gate break; 152*7c478bd9Sstevel@tonic-gate 153*7c478bd9Sstevel@tonic-gate case OPENED: 154*7c478bd9Sstevel@tonic-gate f->state = STARTING; 155*7c478bd9Sstevel@tonic-gate if (f->callbacks->down != NULL) 156*7c478bd9Sstevel@tonic-gate (*f->callbacks->down)(f); 157*7c478bd9Sstevel@tonic-gate break; 158*7c478bd9Sstevel@tonic-gate 159*7c478bd9Sstevel@tonic-gate default: 160*7c478bd9Sstevel@tonic-gate dbglog("%s: Down event in state %s", PROTO_NAME(f), 161*7c478bd9Sstevel@tonic-gate fsm_state(f->state)); 162*7c478bd9Sstevel@tonic-gate } 163*7c478bd9Sstevel@tonic-gate } 164*7c478bd9Sstevel@tonic-gate 165*7c478bd9Sstevel@tonic-gate 166*7c478bd9Sstevel@tonic-gate /* 167*7c478bd9Sstevel@tonic-gate * fsm_open - Link is allowed to come up. 168*7c478bd9Sstevel@tonic-gate */ 169*7c478bd9Sstevel@tonic-gate void 170*7c478bd9Sstevel@tonic-gate fsm_open(f) 171*7c478bd9Sstevel@tonic-gate fsm *f; 172*7c478bd9Sstevel@tonic-gate { 173*7c478bd9Sstevel@tonic-gate switch( f->state ){ 174*7c478bd9Sstevel@tonic-gate case INITIAL: 175*7c478bd9Sstevel@tonic-gate f->state = STARTING; 176*7c478bd9Sstevel@tonic-gate if (f->callbacks->starting != NULL) 177*7c478bd9Sstevel@tonic-gate (*f->callbacks->starting)(f); 178*7c478bd9Sstevel@tonic-gate break; 179*7c478bd9Sstevel@tonic-gate 180*7c478bd9Sstevel@tonic-gate case CLOSED: 181*7c478bd9Sstevel@tonic-gate if( f->flags & OPT_SILENT ) 182*7c478bd9Sstevel@tonic-gate f->state = STOPPED; 183*7c478bd9Sstevel@tonic-gate else { 184*7c478bd9Sstevel@tonic-gate /* Send an initial configure-request */ 185*7c478bd9Sstevel@tonic-gate fsm_sconfreq(f, 0); 186*7c478bd9Sstevel@tonic-gate f->state = REQSENT; 187*7c478bd9Sstevel@tonic-gate } 188*7c478bd9Sstevel@tonic-gate break; 189*7c478bd9Sstevel@tonic-gate 190*7c478bd9Sstevel@tonic-gate case CLOSING: 191*7c478bd9Sstevel@tonic-gate f->state = STOPPING; 192*7c478bd9Sstevel@tonic-gate /*FALLTHROUGH*/ 193*7c478bd9Sstevel@tonic-gate case STOPPING: 194*7c478bd9Sstevel@tonic-gate case STOPPED: 195*7c478bd9Sstevel@tonic-gate case OPENED: 196*7c478bd9Sstevel@tonic-gate if( f->flags & OPT_RESTART ){ 197*7c478bd9Sstevel@tonic-gate fsm_lowerdown(f); 198*7c478bd9Sstevel@tonic-gate fsm_lowerup(f); 199*7c478bd9Sstevel@tonic-gate } 200*7c478bd9Sstevel@tonic-gate break; 201*7c478bd9Sstevel@tonic-gate 202*7c478bd9Sstevel@tonic-gate case STARTING: 203*7c478bd9Sstevel@tonic-gate case REQSENT: 204*7c478bd9Sstevel@tonic-gate case ACKRCVD: 205*7c478bd9Sstevel@tonic-gate case ACKSENT: 206*7c478bd9Sstevel@tonic-gate /* explicitly do nothing here. */ 207*7c478bd9Sstevel@tonic-gate break; 208*7c478bd9Sstevel@tonic-gate } 209*7c478bd9Sstevel@tonic-gate } 210*7c478bd9Sstevel@tonic-gate 211*7c478bd9Sstevel@tonic-gate 212*7c478bd9Sstevel@tonic-gate /* 213*7c478bd9Sstevel@tonic-gate * fsm_close - Start closing connection. 214*7c478bd9Sstevel@tonic-gate * 215*7c478bd9Sstevel@tonic-gate * Cancel timeouts and either initiate close or possibly go directly to 216*7c478bd9Sstevel@tonic-gate * the CLOSED state. 217*7c478bd9Sstevel@tonic-gate */ 218*7c478bd9Sstevel@tonic-gate void 219*7c478bd9Sstevel@tonic-gate fsm_close(f, reason) 220*7c478bd9Sstevel@tonic-gate fsm *f; 221*7c478bd9Sstevel@tonic-gate char *reason; 222*7c478bd9Sstevel@tonic-gate { 223*7c478bd9Sstevel@tonic-gate int prevstate = f->state; 224*7c478bd9Sstevel@tonic-gate 225*7c478bd9Sstevel@tonic-gate f->term_reason = reason; 226*7c478bd9Sstevel@tonic-gate f->term_reason_len = (reason == NULL? 0: strlen(reason)); 227*7c478bd9Sstevel@tonic-gate switch( f->state ){ 228*7c478bd9Sstevel@tonic-gate case STARTING: 229*7c478bd9Sstevel@tonic-gate f->state = INITIAL; 230*7c478bd9Sstevel@tonic-gate if (f->callbacks->finished != NULL) 231*7c478bd9Sstevel@tonic-gate (*f->callbacks->finished)(f); 232*7c478bd9Sstevel@tonic-gate break; 233*7c478bd9Sstevel@tonic-gate 234*7c478bd9Sstevel@tonic-gate case STOPPED: 235*7c478bd9Sstevel@tonic-gate f->state = CLOSED; 236*7c478bd9Sstevel@tonic-gate break; 237*7c478bd9Sstevel@tonic-gate 238*7c478bd9Sstevel@tonic-gate case STOPPING: 239*7c478bd9Sstevel@tonic-gate f->state = CLOSING; 240*7c478bd9Sstevel@tonic-gate break; 241*7c478bd9Sstevel@tonic-gate 242*7c478bd9Sstevel@tonic-gate case REQSENT: 243*7c478bd9Sstevel@tonic-gate case ACKRCVD: 244*7c478bd9Sstevel@tonic-gate case ACKSENT: 245*7c478bd9Sstevel@tonic-gate case OPENED: 246*7c478bd9Sstevel@tonic-gate f->state = CLOSING; 247*7c478bd9Sstevel@tonic-gate if (prevstate != OPENED ) 248*7c478bd9Sstevel@tonic-gate UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ 249*7c478bd9Sstevel@tonic-gate else if (f->callbacks->down != NULL) 250*7c478bd9Sstevel@tonic-gate (*f->callbacks->down)(f); /* Inform upper layers we're down */ 251*7c478bd9Sstevel@tonic-gate /* 252*7c478bd9Sstevel@tonic-gate * Note that this-layer-down means "stop transmitting." 253*7c478bd9Sstevel@tonic-gate * This-layer-finished means "stop everything." 254*7c478bd9Sstevel@tonic-gate */ 255*7c478bd9Sstevel@tonic-gate 256*7c478bd9Sstevel@tonic-gate /* Init restart counter, send Terminate-Request */ 257*7c478bd9Sstevel@tonic-gate f->retransmits = f->maxtermtransmits; 258*7c478bd9Sstevel@tonic-gate fsm_sdata(f, CODE_TERMREQ, f->reqid = ++f->id, 259*7c478bd9Sstevel@tonic-gate (u_char *) f->term_reason, f->term_reason_len); 260*7c478bd9Sstevel@tonic-gate TIMEOUT(fsm_timeout, f, f->timeouttime); 261*7c478bd9Sstevel@tonic-gate --f->retransmits; 262*7c478bd9Sstevel@tonic-gate break; 263*7c478bd9Sstevel@tonic-gate 264*7c478bd9Sstevel@tonic-gate case INITIAL: 265*7c478bd9Sstevel@tonic-gate case CLOSED: 266*7c478bd9Sstevel@tonic-gate case CLOSING: 267*7c478bd9Sstevel@tonic-gate /* explicitly do nothing here. */ 268*7c478bd9Sstevel@tonic-gate break; 269*7c478bd9Sstevel@tonic-gate } 270*7c478bd9Sstevel@tonic-gate } 271*7c478bd9Sstevel@tonic-gate 272*7c478bd9Sstevel@tonic-gate 273*7c478bd9Sstevel@tonic-gate /* 274*7c478bd9Sstevel@tonic-gate * fsm_timeout - Timeout expired. 275*7c478bd9Sstevel@tonic-gate */ 276*7c478bd9Sstevel@tonic-gate static void 277*7c478bd9Sstevel@tonic-gate fsm_timeout(arg) 278*7c478bd9Sstevel@tonic-gate void *arg; 279*7c478bd9Sstevel@tonic-gate { 280*7c478bd9Sstevel@tonic-gate fsm *f = (fsm *) arg; 281*7c478bd9Sstevel@tonic-gate 282*7c478bd9Sstevel@tonic-gate switch (f->state) { 283*7c478bd9Sstevel@tonic-gate case CLOSING: 284*7c478bd9Sstevel@tonic-gate case STOPPING: 285*7c478bd9Sstevel@tonic-gate if( f->retransmits <= 0 ){ 286*7c478bd9Sstevel@tonic-gate /* 287*7c478bd9Sstevel@tonic-gate * We've waited for an ack long enough. Peer probably heard us. 288*7c478bd9Sstevel@tonic-gate */ 289*7c478bd9Sstevel@tonic-gate f->state = (f->state == CLOSING)? CLOSED: STOPPED; 290*7c478bd9Sstevel@tonic-gate if (f->callbacks->finished != NULL) 291*7c478bd9Sstevel@tonic-gate (*f->callbacks->finished)(f); 292*7c478bd9Sstevel@tonic-gate } else { 293*7c478bd9Sstevel@tonic-gate /* Send Terminate-Request */ 294*7c478bd9Sstevel@tonic-gate fsm_sdata(f, CODE_TERMREQ, f->reqid = ++f->id, 295*7c478bd9Sstevel@tonic-gate (u_char *) f->term_reason, f->term_reason_len); 296*7c478bd9Sstevel@tonic-gate TIMEOUT(fsm_timeout, f, f->timeouttime); 297*7c478bd9Sstevel@tonic-gate --f->retransmits; 298*7c478bd9Sstevel@tonic-gate } 299*7c478bd9Sstevel@tonic-gate break; 300*7c478bd9Sstevel@tonic-gate 301*7c478bd9Sstevel@tonic-gate case REQSENT: 302*7c478bd9Sstevel@tonic-gate case ACKRCVD: 303*7c478bd9Sstevel@tonic-gate case ACKSENT: 304*7c478bd9Sstevel@tonic-gate if (f->retransmits <= 0) { 305*7c478bd9Sstevel@tonic-gate warn("%s: timeout sending Config-Requests\n", PROTO_NAME(f)); 306*7c478bd9Sstevel@tonic-gate f->state = STOPPED; 307*7c478bd9Sstevel@tonic-gate if (!(f->flags & OPT_PASSIVE) && f->callbacks->finished != NULL) 308*7c478bd9Sstevel@tonic-gate (*f->callbacks->finished)(f); 309*7c478bd9Sstevel@tonic-gate 310*7c478bd9Sstevel@tonic-gate } else { 311*7c478bd9Sstevel@tonic-gate /* Retransmit the configure-request */ 312*7c478bd9Sstevel@tonic-gate if (f->callbacks->retransmit != NULL) 313*7c478bd9Sstevel@tonic-gate (*f->callbacks->retransmit)(f); 314*7c478bd9Sstevel@tonic-gate fsm_sconfreq(f, 1); /* Re-send Configure-Request */ 315*7c478bd9Sstevel@tonic-gate if( f->state == ACKRCVD ) 316*7c478bd9Sstevel@tonic-gate f->state = REQSENT; 317*7c478bd9Sstevel@tonic-gate } 318*7c478bd9Sstevel@tonic-gate break; 319*7c478bd9Sstevel@tonic-gate 320*7c478bd9Sstevel@tonic-gate default: 321*7c478bd9Sstevel@tonic-gate fatal("%s: Timeout event in state %s!", PROTO_NAME(f), 322*7c478bd9Sstevel@tonic-gate fsm_state(f->state)); 323*7c478bd9Sstevel@tonic-gate } 324*7c478bd9Sstevel@tonic-gate } 325*7c478bd9Sstevel@tonic-gate 326*7c478bd9Sstevel@tonic-gate 327*7c478bd9Sstevel@tonic-gate /* 328*7c478bd9Sstevel@tonic-gate * fsm_input - Input packet. 329*7c478bd9Sstevel@tonic-gate */ 330*7c478bd9Sstevel@tonic-gate void 331*7c478bd9Sstevel@tonic-gate fsm_input(f, inpacket, l) 332*7c478bd9Sstevel@tonic-gate fsm *f; 333*7c478bd9Sstevel@tonic-gate u_char *inpacket; 334*7c478bd9Sstevel@tonic-gate int l; 335*7c478bd9Sstevel@tonic-gate { 336*7c478bd9Sstevel@tonic-gate u_char *inp; 337*7c478bd9Sstevel@tonic-gate u_char code, id; 338*7c478bd9Sstevel@tonic-gate int len; 339*7c478bd9Sstevel@tonic-gate 340*7c478bd9Sstevel@tonic-gate /* 341*7c478bd9Sstevel@tonic-gate * Parse header (code, id and length). 342*7c478bd9Sstevel@tonic-gate * If packet too short, drop it. 343*7c478bd9Sstevel@tonic-gate */ 344*7c478bd9Sstevel@tonic-gate inp = inpacket; 345*7c478bd9Sstevel@tonic-gate if (l < HEADERLEN) { 346*7c478bd9Sstevel@tonic-gate error("%s packet: discard; too small (%d < %d)", PROTO_NAME(f), l, 347*7c478bd9Sstevel@tonic-gate HEADERLEN); 348*7c478bd9Sstevel@tonic-gate return; 349*7c478bd9Sstevel@tonic-gate } 350*7c478bd9Sstevel@tonic-gate GETCHAR(code, inp); 351*7c478bd9Sstevel@tonic-gate GETCHAR(id, inp); 352*7c478bd9Sstevel@tonic-gate GETSHORT(len, inp); 353*7c478bd9Sstevel@tonic-gate if (len < HEADERLEN) { 354*7c478bd9Sstevel@tonic-gate error("%s packet: discard; invalid length (%d < %d)", PROTO_NAME(f), 355*7c478bd9Sstevel@tonic-gate len, HEADERLEN); 356*7c478bd9Sstevel@tonic-gate return; 357*7c478bd9Sstevel@tonic-gate } 358*7c478bd9Sstevel@tonic-gate if (len > l) { 359*7c478bd9Sstevel@tonic-gate error("%s packet: discard; truncated (%d > %d)", PROTO_NAME(f), len, 360*7c478bd9Sstevel@tonic-gate l); 361*7c478bd9Sstevel@tonic-gate return; 362*7c478bd9Sstevel@tonic-gate } 363*7c478bd9Sstevel@tonic-gate len -= HEADERLEN; /* subtract header length */ 364*7c478bd9Sstevel@tonic-gate 365*7c478bd9Sstevel@tonic-gate if (f->state == INITIAL || f->state == STARTING) { 366*7c478bd9Sstevel@tonic-gate dbglog("%s: discarded packet in state %s", PROTO_NAME(f), 367*7c478bd9Sstevel@tonic-gate fsm_state(f->state)); 368*7c478bd9Sstevel@tonic-gate return; 369*7c478bd9Sstevel@tonic-gate } 370*7c478bd9Sstevel@tonic-gate 371*7c478bd9Sstevel@tonic-gate /* 372*7c478bd9Sstevel@tonic-gate * Action depends on code. 373*7c478bd9Sstevel@tonic-gate */ 374*7c478bd9Sstevel@tonic-gate switch (code) { 375*7c478bd9Sstevel@tonic-gate case CODE_CONFREQ: 376*7c478bd9Sstevel@tonic-gate fsm_rconfreq(f, id, inp, len); 377*7c478bd9Sstevel@tonic-gate break; 378*7c478bd9Sstevel@tonic-gate 379*7c478bd9Sstevel@tonic-gate case CODE_CONFACK: 380*7c478bd9Sstevel@tonic-gate fsm_rconfack(f, id, inp, len); 381*7c478bd9Sstevel@tonic-gate break; 382*7c478bd9Sstevel@tonic-gate 383*7c478bd9Sstevel@tonic-gate case CODE_CONFNAK: 384*7c478bd9Sstevel@tonic-gate case CODE_CONFREJ: 385*7c478bd9Sstevel@tonic-gate fsm_rconfnakrej(f, code, id, inp, len); 386*7c478bd9Sstevel@tonic-gate break; 387*7c478bd9Sstevel@tonic-gate 388*7c478bd9Sstevel@tonic-gate case CODE_TERMREQ: 389*7c478bd9Sstevel@tonic-gate fsm_rtermreq(f, id, inp, len); 390*7c478bd9Sstevel@tonic-gate break; 391*7c478bd9Sstevel@tonic-gate 392*7c478bd9Sstevel@tonic-gate case CODE_TERMACK: 393*7c478bd9Sstevel@tonic-gate fsm_rtermack(f); 394*7c478bd9Sstevel@tonic-gate break; 395*7c478bd9Sstevel@tonic-gate 396*7c478bd9Sstevel@tonic-gate case CODE_CODEREJ: 397*7c478bd9Sstevel@tonic-gate fsm_rcoderej(f, inp, len); 398*7c478bd9Sstevel@tonic-gate break; 399*7c478bd9Sstevel@tonic-gate 400*7c478bd9Sstevel@tonic-gate default: 401*7c478bd9Sstevel@tonic-gate if (f->callbacks->extcode == NULL || 402*7c478bd9Sstevel@tonic-gate !(*f->callbacks->extcode)(f, code, id, inp, len)) 403*7c478bd9Sstevel@tonic-gate fsm_sdata(f, CODE_CODEREJ, ++f->id, inpacket, len + HEADERLEN); 404*7c478bd9Sstevel@tonic-gate break; 405*7c478bd9Sstevel@tonic-gate } 406*7c478bd9Sstevel@tonic-gate } 407*7c478bd9Sstevel@tonic-gate 408*7c478bd9Sstevel@tonic-gate 409*7c478bd9Sstevel@tonic-gate /* 410*7c478bd9Sstevel@tonic-gate * fsm_rconfreq - Receive Configure-Request. 411*7c478bd9Sstevel@tonic-gate */ 412*7c478bd9Sstevel@tonic-gate static void 413*7c478bd9Sstevel@tonic-gate fsm_rconfreq(f, id, inp, len) 414*7c478bd9Sstevel@tonic-gate fsm *f; 415*7c478bd9Sstevel@tonic-gate u_char id; 416*7c478bd9Sstevel@tonic-gate u_char *inp; 417*7c478bd9Sstevel@tonic-gate int len; 418*7c478bd9Sstevel@tonic-gate { 419*7c478bd9Sstevel@tonic-gate int code, reject_if_disagree; 420*7c478bd9Sstevel@tonic-gate 421*7c478bd9Sstevel@tonic-gate switch( f->state ){ 422*7c478bd9Sstevel@tonic-gate case CLOSED: 423*7c478bd9Sstevel@tonic-gate /* Go away, we're closed */ 424*7c478bd9Sstevel@tonic-gate fsm_sdata(f, CODE_TERMACK, id, NULL, 0); 425*7c478bd9Sstevel@tonic-gate return; 426*7c478bd9Sstevel@tonic-gate 427*7c478bd9Sstevel@tonic-gate case CLOSING: 428*7c478bd9Sstevel@tonic-gate case STOPPING: 429*7c478bd9Sstevel@tonic-gate dbglog("%s: discarded Configure-Request in state %s", PROTO_NAME(f), 430*7c478bd9Sstevel@tonic-gate fsm_state(f->state)); 431*7c478bd9Sstevel@tonic-gate return; 432*7c478bd9Sstevel@tonic-gate 433*7c478bd9Sstevel@tonic-gate case OPENED: 434*7c478bd9Sstevel@tonic-gate /* Go down and restart negotiation */ 435*7c478bd9Sstevel@tonic-gate if (f->callbacks->down != NULL) 436*7c478bd9Sstevel@tonic-gate (*f->callbacks->down)(f); /* Inform upper layers */ 437*7c478bd9Sstevel@tonic-gate break; 438*7c478bd9Sstevel@tonic-gate } 439*7c478bd9Sstevel@tonic-gate 440*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 441*7c478bd9Sstevel@tonic-gate if (inp >= outpacket_buf && inp < outpacket_buf+PPP_MRU+PPP_HDRLEN) 442*7c478bd9Sstevel@tonic-gate fatal("bad pointer"); 443*7c478bd9Sstevel@tonic-gate #endif 444*7c478bd9Sstevel@tonic-gate 445*7c478bd9Sstevel@tonic-gate /* 446*7c478bd9Sstevel@tonic-gate * Pass the requested configuration options 447*7c478bd9Sstevel@tonic-gate * to protocol-specific code for checking. 448*7c478bd9Sstevel@tonic-gate */ 449*7c478bd9Sstevel@tonic-gate if (f->callbacks->reqci != NULL) { /* Check CI */ 450*7c478bd9Sstevel@tonic-gate reject_if_disagree = (f->nakloops >= f->maxnakloops); 451*7c478bd9Sstevel@tonic-gate code = (*f->callbacks->reqci)(f, inp, &len, reject_if_disagree); 452*7c478bd9Sstevel@tonic-gate } else if (len > 0) 453*7c478bd9Sstevel@tonic-gate code = CODE_CONFREJ; /* Reject all CI */ 454*7c478bd9Sstevel@tonic-gate else 455*7c478bd9Sstevel@tonic-gate code = CODE_CONFACK; 456*7c478bd9Sstevel@tonic-gate 457*7c478bd9Sstevel@tonic-gate /* Allow NCP to do fancy footwork, such as reinitializing. */ 458*7c478bd9Sstevel@tonic-gate if (code <= 0) 459*7c478bd9Sstevel@tonic-gate return; 460*7c478bd9Sstevel@tonic-gate 461*7c478bd9Sstevel@tonic-gate if (f->state == OPENED || f->state == STOPPED) 462*7c478bd9Sstevel@tonic-gate fsm_sconfreq(f, 0); /* Send initial Configure-Request */ 463*7c478bd9Sstevel@tonic-gate 464*7c478bd9Sstevel@tonic-gate /* send the Ack, Nak or Rej to the peer */ 465*7c478bd9Sstevel@tonic-gate fsm_sdata(f, code, id, inp, len); 466*7c478bd9Sstevel@tonic-gate 467*7c478bd9Sstevel@tonic-gate if (code == CODE_CONFACK) { 468*7c478bd9Sstevel@tonic-gate /* RFC 1661 event RCR+ */ 469*7c478bd9Sstevel@tonic-gate if (f->state == ACKRCVD) { 470*7c478bd9Sstevel@tonic-gate UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ 471*7c478bd9Sstevel@tonic-gate f->state = OPENED; 472*7c478bd9Sstevel@tonic-gate if (f->callbacks->up != NULL) 473*7c478bd9Sstevel@tonic-gate (*f->callbacks->up)(f); /* Inform upper layers */ 474*7c478bd9Sstevel@tonic-gate } else 475*7c478bd9Sstevel@tonic-gate f->state = ACKSENT; 476*7c478bd9Sstevel@tonic-gate f->nakloops = 0; 477*7c478bd9Sstevel@tonic-gate 478*7c478bd9Sstevel@tonic-gate } else { 479*7c478bd9Sstevel@tonic-gate /* RFC 1661 event RCR- */ 480*7c478bd9Sstevel@tonic-gate /* (we sent CODE_CONFNAK or CODE_CONFREJ) */ 481*7c478bd9Sstevel@tonic-gate if (f->state != ACKRCVD) 482*7c478bd9Sstevel@tonic-gate f->state = REQSENT; 483*7c478bd9Sstevel@tonic-gate if( code == CODE_CONFNAK ) 484*7c478bd9Sstevel@tonic-gate ++f->nakloops; 485*7c478bd9Sstevel@tonic-gate } 486*7c478bd9Sstevel@tonic-gate } 487*7c478bd9Sstevel@tonic-gate 488*7c478bd9Sstevel@tonic-gate 489*7c478bd9Sstevel@tonic-gate /* 490*7c478bd9Sstevel@tonic-gate * fsm_rconfack - Receive Configure-Ack. 491*7c478bd9Sstevel@tonic-gate */ 492*7c478bd9Sstevel@tonic-gate static void 493*7c478bd9Sstevel@tonic-gate fsm_rconfack(f, id, inp, len) 494*7c478bd9Sstevel@tonic-gate fsm *f; 495*7c478bd9Sstevel@tonic-gate int id; 496*7c478bd9Sstevel@tonic-gate u_char *inp; 497*7c478bd9Sstevel@tonic-gate int len; 498*7c478bd9Sstevel@tonic-gate { 499*7c478bd9Sstevel@tonic-gate if (id != f->reqid || f->seen_ack) /* Expected id? */ 500*7c478bd9Sstevel@tonic-gate return; /* Nope, toss... */ 501*7c478bd9Sstevel@tonic-gate if( !(f->callbacks->ackci != NULL ? (*f->callbacks->ackci)(f, inp, len): 502*7c478bd9Sstevel@tonic-gate (len == 0)) ){ 503*7c478bd9Sstevel@tonic-gate /* Ack is bad - ignore it */ 504*7c478bd9Sstevel@tonic-gate error("Received bad configure-ack: %P", inp, len); 505*7c478bd9Sstevel@tonic-gate return; 506*7c478bd9Sstevel@tonic-gate } 507*7c478bd9Sstevel@tonic-gate f->seen_ack = 1; 508*7c478bd9Sstevel@tonic-gate 509*7c478bd9Sstevel@tonic-gate switch (f->state) { 510*7c478bd9Sstevel@tonic-gate case CLOSED: 511*7c478bd9Sstevel@tonic-gate case STOPPED: 512*7c478bd9Sstevel@tonic-gate fsm_sdata(f, CODE_TERMACK, id, NULL, 0); 513*7c478bd9Sstevel@tonic-gate break; 514*7c478bd9Sstevel@tonic-gate 515*7c478bd9Sstevel@tonic-gate case REQSENT: 516*7c478bd9Sstevel@tonic-gate f->state = ACKRCVD; 517*7c478bd9Sstevel@tonic-gate f->retransmits = f->maxconfreqtransmits; 518*7c478bd9Sstevel@tonic-gate break; 519*7c478bd9Sstevel@tonic-gate 520*7c478bd9Sstevel@tonic-gate case ACKRCVD: 521*7c478bd9Sstevel@tonic-gate /* Huh? an extra valid Ack? oh well... */ 522*7c478bd9Sstevel@tonic-gate UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ 523*7c478bd9Sstevel@tonic-gate fsm_sconfreq(f, 0); 524*7c478bd9Sstevel@tonic-gate f->state = REQSENT; 525*7c478bd9Sstevel@tonic-gate break; 526*7c478bd9Sstevel@tonic-gate 527*7c478bd9Sstevel@tonic-gate case ACKSENT: 528*7c478bd9Sstevel@tonic-gate UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ 529*7c478bd9Sstevel@tonic-gate f->state = OPENED; 530*7c478bd9Sstevel@tonic-gate f->retransmits = f->maxconfreqtransmits; 531*7c478bd9Sstevel@tonic-gate if (f->callbacks->up != NULL) 532*7c478bd9Sstevel@tonic-gate (*f->callbacks->up)(f); /* Inform upper layers */ 533*7c478bd9Sstevel@tonic-gate break; 534*7c478bd9Sstevel@tonic-gate 535*7c478bd9Sstevel@tonic-gate case OPENED: 536*7c478bd9Sstevel@tonic-gate /* Go down and restart negotiation */ 537*7c478bd9Sstevel@tonic-gate fsm_sconfreq(f, 0); /* Send initial Configure-Request */ 538*7c478bd9Sstevel@tonic-gate f->state = REQSENT; 539*7c478bd9Sstevel@tonic-gate if (f->callbacks->down != NULL) 540*7c478bd9Sstevel@tonic-gate (*f->callbacks->down)(f); /* Inform upper layers */ 541*7c478bd9Sstevel@tonic-gate break; 542*7c478bd9Sstevel@tonic-gate } 543*7c478bd9Sstevel@tonic-gate } 544*7c478bd9Sstevel@tonic-gate 545*7c478bd9Sstevel@tonic-gate 546*7c478bd9Sstevel@tonic-gate /* 547*7c478bd9Sstevel@tonic-gate * fsm_rconfnakrej - Receive Configure-Nak or Configure-Reject. 548*7c478bd9Sstevel@tonic-gate */ 549*7c478bd9Sstevel@tonic-gate static void 550*7c478bd9Sstevel@tonic-gate fsm_rconfnakrej(f, code, id, inp, len) 551*7c478bd9Sstevel@tonic-gate fsm *f; 552*7c478bd9Sstevel@tonic-gate int code, id; 553*7c478bd9Sstevel@tonic-gate u_char *inp; 554*7c478bd9Sstevel@tonic-gate int len; 555*7c478bd9Sstevel@tonic-gate { 556*7c478bd9Sstevel@tonic-gate int (*proc) __P((fsm *, u_char *, int)); 557*7c478bd9Sstevel@tonic-gate int ret; 558*7c478bd9Sstevel@tonic-gate 559*7c478bd9Sstevel@tonic-gate if (id != f->reqid || f->seen_ack) /* Expected id? */ 560*7c478bd9Sstevel@tonic-gate return; /* Nope, toss... */ 561*7c478bd9Sstevel@tonic-gate proc = (code == CODE_CONFNAK)? f->callbacks->nakci: f->callbacks->rejci; 562*7c478bd9Sstevel@tonic-gate if (proc == NULL || !(ret = proc(f, inp, len))) { 563*7c478bd9Sstevel@tonic-gate /* Nak/reject is bad - ignore it */ 564*7c478bd9Sstevel@tonic-gate error("Received bad configure-nak/rej: %P", inp, len); 565*7c478bd9Sstevel@tonic-gate return; 566*7c478bd9Sstevel@tonic-gate } 567*7c478bd9Sstevel@tonic-gate f->seen_ack = 1; 568*7c478bd9Sstevel@tonic-gate 569*7c478bd9Sstevel@tonic-gate switch (f->state) { 570*7c478bd9Sstevel@tonic-gate case CLOSED: 571*7c478bd9Sstevel@tonic-gate case STOPPED: 572*7c478bd9Sstevel@tonic-gate fsm_sdata(f, CODE_TERMACK, id, NULL, 0); 573*7c478bd9Sstevel@tonic-gate break; 574*7c478bd9Sstevel@tonic-gate 575*7c478bd9Sstevel@tonic-gate case REQSENT: 576*7c478bd9Sstevel@tonic-gate case ACKSENT: 577*7c478bd9Sstevel@tonic-gate /* They didn't agree to what we wanted - try another request */ 578*7c478bd9Sstevel@tonic-gate UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ 579*7c478bd9Sstevel@tonic-gate if (ret < 0) 580*7c478bd9Sstevel@tonic-gate f->state = STOPPED; /* kludge for stopping CCP */ 581*7c478bd9Sstevel@tonic-gate else 582*7c478bd9Sstevel@tonic-gate fsm_sconfreq(f, 0); /* Send Configure-Request */ 583*7c478bd9Sstevel@tonic-gate break; 584*7c478bd9Sstevel@tonic-gate 585*7c478bd9Sstevel@tonic-gate case ACKRCVD: 586*7c478bd9Sstevel@tonic-gate /* Got a Nak/reject when we had already had an Ack?? oh well... */ 587*7c478bd9Sstevel@tonic-gate UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ 588*7c478bd9Sstevel@tonic-gate fsm_sconfreq(f, 0); 589*7c478bd9Sstevel@tonic-gate f->state = REQSENT; 590*7c478bd9Sstevel@tonic-gate break; 591*7c478bd9Sstevel@tonic-gate 592*7c478bd9Sstevel@tonic-gate case OPENED: 593*7c478bd9Sstevel@tonic-gate /* Go down and restart negotiation */ 594*7c478bd9Sstevel@tonic-gate fsm_sconfreq(f, 0); /* Send initial Configure-Request */ 595*7c478bd9Sstevel@tonic-gate f->state = REQSENT; 596*7c478bd9Sstevel@tonic-gate if (f->callbacks->down != NULL) 597*7c478bd9Sstevel@tonic-gate (*f->callbacks->down)(f); /* Inform upper layers */ 598*7c478bd9Sstevel@tonic-gate break; 599*7c478bd9Sstevel@tonic-gate } 600*7c478bd9Sstevel@tonic-gate } 601*7c478bd9Sstevel@tonic-gate 602*7c478bd9Sstevel@tonic-gate 603*7c478bd9Sstevel@tonic-gate /* 604*7c478bd9Sstevel@tonic-gate * fsm_rtermreq - Receive Terminate-Req. 605*7c478bd9Sstevel@tonic-gate */ 606*7c478bd9Sstevel@tonic-gate static void 607*7c478bd9Sstevel@tonic-gate fsm_rtermreq(f, id, p, len) 608*7c478bd9Sstevel@tonic-gate fsm *f; 609*7c478bd9Sstevel@tonic-gate int id; 610*7c478bd9Sstevel@tonic-gate u_char *p; 611*7c478bd9Sstevel@tonic-gate int len; 612*7c478bd9Sstevel@tonic-gate { 613*7c478bd9Sstevel@tonic-gate switch (f->state) { 614*7c478bd9Sstevel@tonic-gate case ACKRCVD: 615*7c478bd9Sstevel@tonic-gate case ACKSENT: 616*7c478bd9Sstevel@tonic-gate f->state = REQSENT; /* Start over but keep trying */ 617*7c478bd9Sstevel@tonic-gate break; 618*7c478bd9Sstevel@tonic-gate 619*7c478bd9Sstevel@tonic-gate case OPENED: 620*7c478bd9Sstevel@tonic-gate if (len > 0) { 621*7c478bd9Sstevel@tonic-gate info("%s terminated by peer (%0.*v)", PROTO_NAME(f), len, p); 622*7c478bd9Sstevel@tonic-gate } else { 623*7c478bd9Sstevel@tonic-gate info("%s terminated by peer", PROTO_NAME(f)); 624*7c478bd9Sstevel@tonic-gate } 625*7c478bd9Sstevel@tonic-gate f->state = STOPPING; 626*7c478bd9Sstevel@tonic-gate if (f->callbacks->down != NULL) 627*7c478bd9Sstevel@tonic-gate (*f->callbacks->down)(f); /* Inform upper layers */ 628*7c478bd9Sstevel@tonic-gate f->retransmits = 0; 629*7c478bd9Sstevel@tonic-gate TIMEOUT(fsm_timeout, f, f->timeouttime); 630*7c478bd9Sstevel@tonic-gate break; 631*7c478bd9Sstevel@tonic-gate } 632*7c478bd9Sstevel@tonic-gate 633*7c478bd9Sstevel@tonic-gate fsm_sdata(f, CODE_TERMACK, id, NULL, 0); 634*7c478bd9Sstevel@tonic-gate } 635*7c478bd9Sstevel@tonic-gate 636*7c478bd9Sstevel@tonic-gate 637*7c478bd9Sstevel@tonic-gate /* 638*7c478bd9Sstevel@tonic-gate * fsm_rtermack - Receive Terminate-Ack. 639*7c478bd9Sstevel@tonic-gate */ 640*7c478bd9Sstevel@tonic-gate static void 641*7c478bd9Sstevel@tonic-gate fsm_rtermack(f) 642*7c478bd9Sstevel@tonic-gate fsm *f; 643*7c478bd9Sstevel@tonic-gate { 644*7c478bd9Sstevel@tonic-gate switch (f->state) { 645*7c478bd9Sstevel@tonic-gate case CLOSING: 646*7c478bd9Sstevel@tonic-gate UNTIMEOUT(fsm_timeout, f); 647*7c478bd9Sstevel@tonic-gate f->state = CLOSED; 648*7c478bd9Sstevel@tonic-gate if (f->callbacks->finished != NULL) 649*7c478bd9Sstevel@tonic-gate (*f->callbacks->finished)(f); 650*7c478bd9Sstevel@tonic-gate break; 651*7c478bd9Sstevel@tonic-gate case STOPPING: 652*7c478bd9Sstevel@tonic-gate UNTIMEOUT(fsm_timeout, f); 653*7c478bd9Sstevel@tonic-gate f->state = STOPPED; 654*7c478bd9Sstevel@tonic-gate if (f->callbacks->finished != NULL) 655*7c478bd9Sstevel@tonic-gate (*f->callbacks->finished)(f); 656*7c478bd9Sstevel@tonic-gate break; 657*7c478bd9Sstevel@tonic-gate 658*7c478bd9Sstevel@tonic-gate case ACKRCVD: 659*7c478bd9Sstevel@tonic-gate f->state = REQSENT; 660*7c478bd9Sstevel@tonic-gate break; 661*7c478bd9Sstevel@tonic-gate 662*7c478bd9Sstevel@tonic-gate case OPENED: 663*7c478bd9Sstevel@tonic-gate fsm_sconfreq(f, 0); 664*7c478bd9Sstevel@tonic-gate f->state = REQSENT; 665*7c478bd9Sstevel@tonic-gate if (f->callbacks->down != NULL) 666*7c478bd9Sstevel@tonic-gate (*f->callbacks->down)(f); /* Inform upper layers */ 667*7c478bd9Sstevel@tonic-gate break; 668*7c478bd9Sstevel@tonic-gate } 669*7c478bd9Sstevel@tonic-gate } 670*7c478bd9Sstevel@tonic-gate 671*7c478bd9Sstevel@tonic-gate 672*7c478bd9Sstevel@tonic-gate /* 673*7c478bd9Sstevel@tonic-gate * fsm_rcoderej - Receive a Code-Reject. 674*7c478bd9Sstevel@tonic-gate */ 675*7c478bd9Sstevel@tonic-gate static void 676*7c478bd9Sstevel@tonic-gate fsm_rcoderej(f, inp, len) 677*7c478bd9Sstevel@tonic-gate fsm *f; 678*7c478bd9Sstevel@tonic-gate u_char *inp; 679*7c478bd9Sstevel@tonic-gate int len; 680*7c478bd9Sstevel@tonic-gate { 681*7c478bd9Sstevel@tonic-gate u_char code, id; 682*7c478bd9Sstevel@tonic-gate int seriouserr; 683*7c478bd9Sstevel@tonic-gate 684*7c478bd9Sstevel@tonic-gate if (len < HEADERLEN) { 685*7c478bd9Sstevel@tonic-gate error("%s: Code-Reject too short (%d < %d)", PROTO_NAME(f), len, 686*7c478bd9Sstevel@tonic-gate HEADERLEN); 687*7c478bd9Sstevel@tonic-gate return; 688*7c478bd9Sstevel@tonic-gate } 689*7c478bd9Sstevel@tonic-gate GETCHAR(code, inp); 690*7c478bd9Sstevel@tonic-gate GETCHAR(id, inp); 691*7c478bd9Sstevel@tonic-gate len -= 2; 692*7c478bd9Sstevel@tonic-gate warn("%s: Rcvd Code-Reject for %s id %d", PROTO_NAME(f), 693*7c478bd9Sstevel@tonic-gate code_name(code,0), id); 694*7c478bd9Sstevel@tonic-gate 695*7c478bd9Sstevel@tonic-gate setbit(f->codemask, code); 696*7c478bd9Sstevel@tonic-gate 697*7c478bd9Sstevel@tonic-gate /* Let the protocol know what happened. */ 698*7c478bd9Sstevel@tonic-gate if (f->callbacks->codereject != NULL) { 699*7c478bd9Sstevel@tonic-gate seriouserr = (*f->callbacks->codereject)(f,code,id,inp,len); 700*7c478bd9Sstevel@tonic-gate } else { 701*7c478bd9Sstevel@tonic-gate /* 702*7c478bd9Sstevel@tonic-gate * By default, it's RXJ- for well-known codes and RXJ+ for 703*7c478bd9Sstevel@tonic-gate * unknown ones. 704*7c478bd9Sstevel@tonic-gate */ 705*7c478bd9Sstevel@tonic-gate seriouserr = (code >= CODE_CONFREQ && code <= CODE_CODEREJ); 706*7c478bd9Sstevel@tonic-gate } 707*7c478bd9Sstevel@tonic-gate 708*7c478bd9Sstevel@tonic-gate if (seriouserr) { 709*7c478bd9Sstevel@tonic-gate /* RXJ- -- shut down the protocol. */ 710*7c478bd9Sstevel@tonic-gate switch (f->state) { 711*7c478bd9Sstevel@tonic-gate case CLOSING: 712*7c478bd9Sstevel@tonic-gate UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ 713*7c478bd9Sstevel@tonic-gate /*FALLTHROUGH*/ 714*7c478bd9Sstevel@tonic-gate case CLOSED: 715*7c478bd9Sstevel@tonic-gate f->state = CLOSED; 716*7c478bd9Sstevel@tonic-gate if (f->callbacks->finished != NULL) 717*7c478bd9Sstevel@tonic-gate (*f->callbacks->finished)(f); 718*7c478bd9Sstevel@tonic-gate break; 719*7c478bd9Sstevel@tonic-gate 720*7c478bd9Sstevel@tonic-gate case STOPPING: 721*7c478bd9Sstevel@tonic-gate case REQSENT: 722*7c478bd9Sstevel@tonic-gate case ACKRCVD: 723*7c478bd9Sstevel@tonic-gate case ACKSENT: 724*7c478bd9Sstevel@tonic-gate UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ 725*7c478bd9Sstevel@tonic-gate f->state = STOPPED; 726*7c478bd9Sstevel@tonic-gate /*FALLTHROUGH*/ 727*7c478bd9Sstevel@tonic-gate case STOPPED: 728*7c478bd9Sstevel@tonic-gate if (f->callbacks->finished != NULL) 729*7c478bd9Sstevel@tonic-gate (*f->callbacks->finished)(f); 730*7c478bd9Sstevel@tonic-gate break; 731*7c478bd9Sstevel@tonic-gate 732*7c478bd9Sstevel@tonic-gate case OPENED: 733*7c478bd9Sstevel@tonic-gate f->state = STOPPING; 734*7c478bd9Sstevel@tonic-gate if (f->callbacks->down != NULL) 735*7c478bd9Sstevel@tonic-gate (*f->callbacks->down)(f); 736*7c478bd9Sstevel@tonic-gate 737*7c478bd9Sstevel@tonic-gate if (f->term_reason == NULL) { 738*7c478bd9Sstevel@tonic-gate f->term_reason = "unacceptable Code-Reject received"; 739*7c478bd9Sstevel@tonic-gate f->term_reason_len = strlen(f->term_reason); 740*7c478bd9Sstevel@tonic-gate } 741*7c478bd9Sstevel@tonic-gate 742*7c478bd9Sstevel@tonic-gate /* Init restart counter, send Terminate-Request */ 743*7c478bd9Sstevel@tonic-gate f->retransmits = f->maxtermtransmits; 744*7c478bd9Sstevel@tonic-gate fsm_sdata(f, CODE_TERMREQ, f->reqid = ++f->id, 745*7c478bd9Sstevel@tonic-gate (u_char *) f->term_reason, f->term_reason_len); 746*7c478bd9Sstevel@tonic-gate TIMEOUT(fsm_timeout, f, f->timeouttime); 747*7c478bd9Sstevel@tonic-gate --f->retransmits; 748*7c478bd9Sstevel@tonic-gate break; 749*7c478bd9Sstevel@tonic-gate 750*7c478bd9Sstevel@tonic-gate default: 751*7c478bd9Sstevel@tonic-gate fatal("state error"); 752*7c478bd9Sstevel@tonic-gate } 753*7c478bd9Sstevel@tonic-gate } else { 754*7c478bd9Sstevel@tonic-gate /* RXJ+ -- just back up from Ack-Rcvd to Req-Sent. */ 755*7c478bd9Sstevel@tonic-gate if (f->state == ACKRCVD) 756*7c478bd9Sstevel@tonic-gate f->state = REQSENT; 757*7c478bd9Sstevel@tonic-gate } 758*7c478bd9Sstevel@tonic-gate } 759*7c478bd9Sstevel@tonic-gate 760*7c478bd9Sstevel@tonic-gate 761*7c478bd9Sstevel@tonic-gate /* 762*7c478bd9Sstevel@tonic-gate * fsm_protreject - Peer doesn't speak this protocol. 763*7c478bd9Sstevel@tonic-gate * 764*7c478bd9Sstevel@tonic-gate * Treat this as a catastrophic error (RXJ-). 765*7c478bd9Sstevel@tonic-gate */ 766*7c478bd9Sstevel@tonic-gate void 767*7c478bd9Sstevel@tonic-gate fsm_protreject(f) 768*7c478bd9Sstevel@tonic-gate fsm *f; 769*7c478bd9Sstevel@tonic-gate { 770*7c478bd9Sstevel@tonic-gate switch( f->state ){ 771*7c478bd9Sstevel@tonic-gate case CLOSING: 772*7c478bd9Sstevel@tonic-gate UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ 773*7c478bd9Sstevel@tonic-gate /*FALLTHROUGH*/ 774*7c478bd9Sstevel@tonic-gate case CLOSED: 775*7c478bd9Sstevel@tonic-gate f->state = CLOSED; 776*7c478bd9Sstevel@tonic-gate if (f->callbacks->finished != NULL) 777*7c478bd9Sstevel@tonic-gate (*f->callbacks->finished)(f); 778*7c478bd9Sstevel@tonic-gate break; 779*7c478bd9Sstevel@tonic-gate 780*7c478bd9Sstevel@tonic-gate case STOPPING: 781*7c478bd9Sstevel@tonic-gate case REQSENT: 782*7c478bd9Sstevel@tonic-gate case ACKRCVD: 783*7c478bd9Sstevel@tonic-gate case ACKSENT: 784*7c478bd9Sstevel@tonic-gate UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ 785*7c478bd9Sstevel@tonic-gate /*FALLTHROUGH*/ 786*7c478bd9Sstevel@tonic-gate case STOPPED: 787*7c478bd9Sstevel@tonic-gate f->state = STOPPED; 788*7c478bd9Sstevel@tonic-gate if (f->callbacks->finished != NULL) 789*7c478bd9Sstevel@tonic-gate (*f->callbacks->finished)(f); 790*7c478bd9Sstevel@tonic-gate break; 791*7c478bd9Sstevel@tonic-gate 792*7c478bd9Sstevel@tonic-gate case OPENED: 793*7c478bd9Sstevel@tonic-gate f->state = STOPPING; 794*7c478bd9Sstevel@tonic-gate if (f->callbacks->down != NULL) 795*7c478bd9Sstevel@tonic-gate (*f->callbacks->down)(f); 796*7c478bd9Sstevel@tonic-gate 797*7c478bd9Sstevel@tonic-gate /* Init restart counter, send Terminate-Request */ 798*7c478bd9Sstevel@tonic-gate f->retransmits = f->maxtermtransmits; 799*7c478bd9Sstevel@tonic-gate fsm_sdata(f, CODE_TERMREQ, f->reqid = ++f->id, 800*7c478bd9Sstevel@tonic-gate (u_char *) f->term_reason, f->term_reason_len); 801*7c478bd9Sstevel@tonic-gate TIMEOUT(fsm_timeout, f, f->timeouttime); 802*7c478bd9Sstevel@tonic-gate --f->retransmits; 803*7c478bd9Sstevel@tonic-gate break; 804*7c478bd9Sstevel@tonic-gate 805*7c478bd9Sstevel@tonic-gate default: 806*7c478bd9Sstevel@tonic-gate dbglog("%s: Protocol-Reject in state %s", PROTO_NAME(f), 807*7c478bd9Sstevel@tonic-gate fsm_state(f->state)); 808*7c478bd9Sstevel@tonic-gate } 809*7c478bd9Sstevel@tonic-gate } 810*7c478bd9Sstevel@tonic-gate 811*7c478bd9Sstevel@tonic-gate 812*7c478bd9Sstevel@tonic-gate /* 813*7c478bd9Sstevel@tonic-gate * fsm_sconfreq - Send a Configure-Request. 814*7c478bd9Sstevel@tonic-gate */ 815*7c478bd9Sstevel@tonic-gate static void 816*7c478bd9Sstevel@tonic-gate fsm_sconfreq(f, retransmit) 817*7c478bd9Sstevel@tonic-gate fsm *f; 818*7c478bd9Sstevel@tonic-gate int retransmit; 819*7c478bd9Sstevel@tonic-gate { 820*7c478bd9Sstevel@tonic-gate u_char *outp; 821*7c478bd9Sstevel@tonic-gate int cilen; 822*7c478bd9Sstevel@tonic-gate 823*7c478bd9Sstevel@tonic-gate if( f->state != REQSENT && f->state != ACKRCVD && f->state != ACKSENT ){ 824*7c478bd9Sstevel@tonic-gate /* Not currently negotiating - reset options */ 825*7c478bd9Sstevel@tonic-gate if (f->callbacks->resetci != NULL) 826*7c478bd9Sstevel@tonic-gate (*f->callbacks->resetci)(f); 827*7c478bd9Sstevel@tonic-gate f->nakloops = 0; 828*7c478bd9Sstevel@tonic-gate } 829*7c478bd9Sstevel@tonic-gate 830*7c478bd9Sstevel@tonic-gate if( !retransmit ){ 831*7c478bd9Sstevel@tonic-gate /* New request - reset retransmission counter, use new ID */ 832*7c478bd9Sstevel@tonic-gate f->retransmits = f->maxconfreqtransmits; 833*7c478bd9Sstevel@tonic-gate f->reqid = ++f->id; 834*7c478bd9Sstevel@tonic-gate } 835*7c478bd9Sstevel@tonic-gate 836*7c478bd9Sstevel@tonic-gate f->seen_ack = 0; 837*7c478bd9Sstevel@tonic-gate 838*7c478bd9Sstevel@tonic-gate /* 839*7c478bd9Sstevel@tonic-gate * Make up the request packet 840*7c478bd9Sstevel@tonic-gate */ 841*7c478bd9Sstevel@tonic-gate outp = outpacket_buf + PPP_HDRLEN + HEADERLEN; 842*7c478bd9Sstevel@tonic-gate if (f->callbacks->cilen != NULL) { 843*7c478bd9Sstevel@tonic-gate cilen = (*f->callbacks->cilen)(f); 844*7c478bd9Sstevel@tonic-gate if (cilen > peer_mru[f->unit] - HEADERLEN) 845*7c478bd9Sstevel@tonic-gate cilen = peer_mru[f->unit] - HEADERLEN; 846*7c478bd9Sstevel@tonic-gate } else { 847*7c478bd9Sstevel@tonic-gate cilen = peer_mru[f->unit] - HEADERLEN; 848*7c478bd9Sstevel@tonic-gate } 849*7c478bd9Sstevel@tonic-gate 850*7c478bd9Sstevel@tonic-gate if (f->callbacks->addci != NULL) 851*7c478bd9Sstevel@tonic-gate (*f->callbacks->addci)(f, outp, &cilen); 852*7c478bd9Sstevel@tonic-gate else 853*7c478bd9Sstevel@tonic-gate cilen = 0; 854*7c478bd9Sstevel@tonic-gate 855*7c478bd9Sstevel@tonic-gate /* send the request to our peer */ 856*7c478bd9Sstevel@tonic-gate fsm_sdata(f, CODE_CONFREQ, f->reqid, outp, cilen); 857*7c478bd9Sstevel@tonic-gate 858*7c478bd9Sstevel@tonic-gate /* start the retransmit timer */ 859*7c478bd9Sstevel@tonic-gate --f->retransmits; 860*7c478bd9Sstevel@tonic-gate TIMEOUT(fsm_timeout, f, f->timeouttime); 861*7c478bd9Sstevel@tonic-gate } 862*7c478bd9Sstevel@tonic-gate 863*7c478bd9Sstevel@tonic-gate 864*7c478bd9Sstevel@tonic-gate /* 865*7c478bd9Sstevel@tonic-gate * fsm_sdata - Send some data. 866*7c478bd9Sstevel@tonic-gate * 867*7c478bd9Sstevel@tonic-gate * Used for all packets sent to our peer by this module. 868*7c478bd9Sstevel@tonic-gate */ 869*7c478bd9Sstevel@tonic-gate void 870*7c478bd9Sstevel@tonic-gate fsm_sdata(f, code, id, data, datalen) 871*7c478bd9Sstevel@tonic-gate fsm *f; 872*7c478bd9Sstevel@tonic-gate u_char code, id; 873*7c478bd9Sstevel@tonic-gate u_char *data; 874*7c478bd9Sstevel@tonic-gate int datalen; 875*7c478bd9Sstevel@tonic-gate { 876*7c478bd9Sstevel@tonic-gate u_char *outp; 877*7c478bd9Sstevel@tonic-gate int outlen; 878*7c478bd9Sstevel@tonic-gate 879*7c478bd9Sstevel@tonic-gate if (isset(f->codemask,code)) { 880*7c478bd9Sstevel@tonic-gate dbglog("%s: Peer has rejected %s; not sending another", 881*7c478bd9Sstevel@tonic-gate PROTO_NAME(f), code_name(code,0)); 882*7c478bd9Sstevel@tonic-gate return; 883*7c478bd9Sstevel@tonic-gate } 884*7c478bd9Sstevel@tonic-gate 885*7c478bd9Sstevel@tonic-gate /* Adjust length to be smaller than MTU */ 886*7c478bd9Sstevel@tonic-gate outp = outpacket_buf; 887*7c478bd9Sstevel@tonic-gate if (datalen > peer_mru[f->unit] - HEADERLEN) 888*7c478bd9Sstevel@tonic-gate datalen = peer_mru[f->unit] - HEADERLEN; 889*7c478bd9Sstevel@tonic-gate if (datalen && data != outp + PPP_HDRLEN + HEADERLEN) 890*7c478bd9Sstevel@tonic-gate BCOPY(data, outp + PPP_HDRLEN + HEADERLEN, datalen); 891*7c478bd9Sstevel@tonic-gate outlen = datalen + HEADERLEN; 892*7c478bd9Sstevel@tonic-gate MAKEHEADER(outp, f->protocol); 893*7c478bd9Sstevel@tonic-gate PUTCHAR(code, outp); 894*7c478bd9Sstevel@tonic-gate PUTCHAR(id, outp); 895*7c478bd9Sstevel@tonic-gate PUTSHORT(outlen, outp); 896*7c478bd9Sstevel@tonic-gate output(f->unit, outpacket_buf, outlen + PPP_HDRLEN); 897*7c478bd9Sstevel@tonic-gate } 898*7c478bd9Sstevel@tonic-gate 899*7c478bd9Sstevel@tonic-gate /* 900*7c478bd9Sstevel@tonic-gate * fsm_setpeermru - Set our idea of the peer's mru 901*7c478bd9Sstevel@tonic-gate * 902*7c478bd9Sstevel@tonic-gate * Used by routines in lcp.c which negotiate this value. 903*7c478bd9Sstevel@tonic-gate */ 904*7c478bd9Sstevel@tonic-gate void 905*7c478bd9Sstevel@tonic-gate fsm_setpeermru(unit, mru) 906*7c478bd9Sstevel@tonic-gate int unit; 907*7c478bd9Sstevel@tonic-gate int mru; 908*7c478bd9Sstevel@tonic-gate { 909*7c478bd9Sstevel@tonic-gate if (unit >= NUM_PPP) { 910*7c478bd9Sstevel@tonic-gate dbglog("fsm_setpeermru: unit out of bounds"); 911*7c478bd9Sstevel@tonic-gate } else { 912*7c478bd9Sstevel@tonic-gate peer_mru[unit] = mru; 913*7c478bd9Sstevel@tonic-gate } 914*7c478bd9Sstevel@tonic-gate } 915