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 *
fsm_state(int statenum)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
fsm_init(f)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
fsm_lowerup(f)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
fsm_lowerdown(f)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
fsm_open(f)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
fsm_close(f,reason)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
fsm_timeout(arg)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
fsm_input(f,inpacket,l)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
fsm_rconfreq(f,id,inp,len)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
fsm_rconfack(f,id,inp,len)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
fsm_rconfnakrej(f,code,id,inp,len)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
fsm_rtermreq(f,id,p,len)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
fsm_rtermack(f)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
fsm_rcoderej(f,inp,len)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
fsm_protreject(f)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
fsm_sconfreq(f,retransmit)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
fsm_sdata(f,code,id,data,datalen)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
fsm_setpeermru(unit,mru)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