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