xref: /titanic_51/usr/src/cmd/cmd-inet/usr.bin/pppd/ccp.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * ccp.c - PPP Compression Control Protocol.
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * Copyright (c) 2000 by Sun Microsystems, Inc.
5*7c478bd9Sstevel@tonic-gate  * All rights reserved.
6*7c478bd9Sstevel@tonic-gate  *
7*7c478bd9Sstevel@tonic-gate  * Copyright (c) 1994 The Australian National University.
8*7c478bd9Sstevel@tonic-gate  * All rights reserved.
9*7c478bd9Sstevel@tonic-gate  *
10*7c478bd9Sstevel@tonic-gate  * Permission to use, copy, modify, and distribute this software and its
11*7c478bd9Sstevel@tonic-gate  * documentation is hereby granted, provided that the above copyright
12*7c478bd9Sstevel@tonic-gate  * notice appears in all copies.  This software is provided without any
13*7c478bd9Sstevel@tonic-gate  * warranty, express or implied. The Australian National University
14*7c478bd9Sstevel@tonic-gate  * makes no representations about the suitability of this software for
15*7c478bd9Sstevel@tonic-gate  * any purpose.
16*7c478bd9Sstevel@tonic-gate  *
17*7c478bd9Sstevel@tonic-gate  * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
18*7c478bd9Sstevel@tonic-gate  * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
19*7c478bd9Sstevel@tonic-gate  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
20*7c478bd9Sstevel@tonic-gate  * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
21*7c478bd9Sstevel@tonic-gate  * OF SUCH DAMAGE.
22*7c478bd9Sstevel@tonic-gate  *
23*7c478bd9Sstevel@tonic-gate  * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
24*7c478bd9Sstevel@tonic-gate  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
25*7c478bd9Sstevel@tonic-gate  * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
26*7c478bd9Sstevel@tonic-gate  * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
27*7c478bd9Sstevel@tonic-gate  * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
28*7c478bd9Sstevel@tonic-gate  * OR MODIFICATIONS.
29*7c478bd9Sstevel@tonic-gate  */
30*7c478bd9Sstevel@tonic-gate 
31*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
32*7c478bd9Sstevel@tonic-gate #define RCSID	"$Id: ccp.c,v 1.30 2000/04/15 01:27:11 masputra Exp $"
33*7c478bd9Sstevel@tonic-gate 
34*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
35*7c478bd9Sstevel@tonic-gate #include <string.h>
36*7c478bd9Sstevel@tonic-gate 
37*7c478bd9Sstevel@tonic-gate #include "pppd.h"
38*7c478bd9Sstevel@tonic-gate #include "fsm.h"
39*7c478bd9Sstevel@tonic-gate #include "ccp.h"
40*7c478bd9Sstevel@tonic-gate #include <net/ppp-comp.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 /*
47*7c478bd9Sstevel@tonic-gate  * Command-line options.
48*7c478bd9Sstevel@tonic-gate  */
49*7c478bd9Sstevel@tonic-gate static int setbsdcomp __P((char **, option_t *));
50*7c478bd9Sstevel@tonic-gate static int setdeflate __P((char **, option_t *));
51*7c478bd9Sstevel@tonic-gate 
52*7c478bd9Sstevel@tonic-gate static option_t ccp_option_list[] = {
53*7c478bd9Sstevel@tonic-gate     { "noccp", o_bool, &ccp_protent.enabled_flag,
54*7c478bd9Sstevel@tonic-gate       "Disable CCP negotiation" },
55*7c478bd9Sstevel@tonic-gate     { "-ccp", o_bool, &ccp_protent.enabled_flag,
56*7c478bd9Sstevel@tonic-gate       "Disable CCP negotiation" },
57*7c478bd9Sstevel@tonic-gate     { "bsdcomp", o_special, (void *)setbsdcomp,
58*7c478bd9Sstevel@tonic-gate       "Request BSD-Compress packet compression" },
59*7c478bd9Sstevel@tonic-gate     { "nobsdcomp", o_bool, &ccp_wantoptions[0].bsd_compress,
60*7c478bd9Sstevel@tonic-gate       "don't allow BSD-Compress", OPT_A2COPY,
61*7c478bd9Sstevel@tonic-gate       &ccp_allowoptions[0].bsd_compress },
62*7c478bd9Sstevel@tonic-gate     { "-bsdcomp", o_bool, &ccp_wantoptions[0].bsd_compress,
63*7c478bd9Sstevel@tonic-gate       "don't allow BSD-Compress", OPT_A2COPY,
64*7c478bd9Sstevel@tonic-gate       &ccp_allowoptions[0].bsd_compress },
65*7c478bd9Sstevel@tonic-gate     { "deflate", o_special, (void *)setdeflate,
66*7c478bd9Sstevel@tonic-gate       "request Deflate compression" },
67*7c478bd9Sstevel@tonic-gate     { "nodeflate", o_bool, &ccp_wantoptions[0].deflate,
68*7c478bd9Sstevel@tonic-gate       "don't allow Deflate compression", OPT_A2COPY,
69*7c478bd9Sstevel@tonic-gate       &ccp_allowoptions[0].deflate },
70*7c478bd9Sstevel@tonic-gate     { "-deflate", o_bool, &ccp_wantoptions[0].deflate,
71*7c478bd9Sstevel@tonic-gate       "don't allow Deflate compression", OPT_A2COPY,
72*7c478bd9Sstevel@tonic-gate       &ccp_allowoptions[0].deflate },
73*7c478bd9Sstevel@tonic-gate     { "nodeflatedraft", o_bool, &ccp_wantoptions[0].deflate_draft,
74*7c478bd9Sstevel@tonic-gate       "don't use draft deflate #", OPT_A2COPY,
75*7c478bd9Sstevel@tonic-gate       &ccp_allowoptions[0].deflate_draft },
76*7c478bd9Sstevel@tonic-gate     { "predictor1", o_bool, &ccp_wantoptions[0].predictor_1,
77*7c478bd9Sstevel@tonic-gate       "request Predictor-1", 1, &ccp_allowoptions[0].predictor_1 },
78*7c478bd9Sstevel@tonic-gate     { "nopredictor1", o_bool, &ccp_wantoptions[0].predictor_1,
79*7c478bd9Sstevel@tonic-gate       "don't allow Predictor-1", OPT_A2COPY,
80*7c478bd9Sstevel@tonic-gate       &ccp_allowoptions[0].predictor_1 },
81*7c478bd9Sstevel@tonic-gate     { "-predictor1", o_bool, &ccp_wantoptions[0].predictor_1,
82*7c478bd9Sstevel@tonic-gate       "don't allow Predictor-1", OPT_A2COPY,
83*7c478bd9Sstevel@tonic-gate       &ccp_allowoptions[0].predictor_1 },
84*7c478bd9Sstevel@tonic-gate 
85*7c478bd9Sstevel@tonic-gate     { NULL }
86*7c478bd9Sstevel@tonic-gate };
87*7c478bd9Sstevel@tonic-gate 
88*7c478bd9Sstevel@tonic-gate /*
89*7c478bd9Sstevel@tonic-gate  * Protocol entry points from main code.
90*7c478bd9Sstevel@tonic-gate  */
91*7c478bd9Sstevel@tonic-gate static void ccp_init __P((int unit));
92*7c478bd9Sstevel@tonic-gate static void ccp_open __P((int unit));
93*7c478bd9Sstevel@tonic-gate static void ccp_close __P((int unit, char *));
94*7c478bd9Sstevel@tonic-gate static void ccp_lowerup __P((int unit));
95*7c478bd9Sstevel@tonic-gate static void ccp_lowerdown __P((int));
96*7c478bd9Sstevel@tonic-gate static void ccp_input __P((int unit, u_char *pkt, int len));
97*7c478bd9Sstevel@tonic-gate static void ccp_protrej __P((int unit));
98*7c478bd9Sstevel@tonic-gate static int  ccp_printpkt __P((u_char *pkt, int len,
99*7c478bd9Sstevel@tonic-gate 			      void (*printer) __P((void *, const char *, ...)),
100*7c478bd9Sstevel@tonic-gate 			      void *arg));
101*7c478bd9Sstevel@tonic-gate static void ccp_datainput __P((int unit, u_char *pkt, int len));
102*7c478bd9Sstevel@tonic-gate 
103*7c478bd9Sstevel@tonic-gate struct protent ccp_protent = {
104*7c478bd9Sstevel@tonic-gate     PPP_CCP,
105*7c478bd9Sstevel@tonic-gate     ccp_init,
106*7c478bd9Sstevel@tonic-gate     ccp_input,
107*7c478bd9Sstevel@tonic-gate     ccp_protrej,
108*7c478bd9Sstevel@tonic-gate     ccp_lowerup,
109*7c478bd9Sstevel@tonic-gate     ccp_lowerdown,
110*7c478bd9Sstevel@tonic-gate     ccp_open,
111*7c478bd9Sstevel@tonic-gate     ccp_close,
112*7c478bd9Sstevel@tonic-gate     ccp_printpkt,
113*7c478bd9Sstevel@tonic-gate     ccp_datainput,
114*7c478bd9Sstevel@tonic-gate     1,
115*7c478bd9Sstevel@tonic-gate     "CCP",
116*7c478bd9Sstevel@tonic-gate     "Compressed",
117*7c478bd9Sstevel@tonic-gate     ccp_option_list,
118*7c478bd9Sstevel@tonic-gate     NULL,
119*7c478bd9Sstevel@tonic-gate     NULL,
120*7c478bd9Sstevel@tonic-gate     NULL
121*7c478bd9Sstevel@tonic-gate };
122*7c478bd9Sstevel@tonic-gate 
123*7c478bd9Sstevel@tonic-gate fsm ccp_fsm[NUM_PPP];
124*7c478bd9Sstevel@tonic-gate ccp_options ccp_wantoptions[NUM_PPP];	/* what to request the peer to use */
125*7c478bd9Sstevel@tonic-gate ccp_options ccp_gotoptions[NUM_PPP];	/* what the peer agreed to do */
126*7c478bd9Sstevel@tonic-gate ccp_options ccp_allowoptions[NUM_PPP];	/* what we'll agree to do */
127*7c478bd9Sstevel@tonic-gate ccp_options ccp_hisoptions[NUM_PPP];	/* what we agreed to do */
128*7c478bd9Sstevel@tonic-gate 
129*7c478bd9Sstevel@tonic-gate /*
130*7c478bd9Sstevel@tonic-gate  * Callbacks for fsm code.
131*7c478bd9Sstevel@tonic-gate  */
132*7c478bd9Sstevel@tonic-gate static void ccp_resetci __P((fsm *));
133*7c478bd9Sstevel@tonic-gate static int  ccp_cilen __P((fsm *));
134*7c478bd9Sstevel@tonic-gate static void ccp_addci __P((fsm *, u_char *, int *));
135*7c478bd9Sstevel@tonic-gate static int  ccp_ackci __P((fsm *, u_char *, int));
136*7c478bd9Sstevel@tonic-gate static int  ccp_nakci __P((fsm *, u_char *, int));
137*7c478bd9Sstevel@tonic-gate static int  ccp_rejci __P((fsm *, u_char *, int));
138*7c478bd9Sstevel@tonic-gate static int  ccp_reqci __P((fsm *, u_char *, int *, int));
139*7c478bd9Sstevel@tonic-gate static void ccp_up __P((fsm *));
140*7c478bd9Sstevel@tonic-gate static void ccp_down __P((fsm *));
141*7c478bd9Sstevel@tonic-gate static int  ccp_extcode __P((fsm *, int, int, u_char *, int));
142*7c478bd9Sstevel@tonic-gate static int  ccp_codereject __P((fsm *p, int code, int id, u_char *inp,
143*7c478bd9Sstevel@tonic-gate     int len));
144*7c478bd9Sstevel@tonic-gate 
145*7c478bd9Sstevel@tonic-gate static fsm_callbacks ccp_callbacks = {
146*7c478bd9Sstevel@tonic-gate     ccp_resetci,		/* Reset our Configuration Information */
147*7c478bd9Sstevel@tonic-gate     ccp_cilen,                  /* Length of our Configuration Information */
148*7c478bd9Sstevel@tonic-gate     ccp_addci,                  /* Add our Configuration Information */
149*7c478bd9Sstevel@tonic-gate     ccp_ackci,                  /* ACK our Configuration Information */
150*7c478bd9Sstevel@tonic-gate     ccp_nakci,                  /* NAK our Configuration Information */
151*7c478bd9Sstevel@tonic-gate     ccp_rejci,                  /* Reject our Configuration Information */
152*7c478bd9Sstevel@tonic-gate     ccp_reqci,                  /* Request peer's Configuration Information */
153*7c478bd9Sstevel@tonic-gate     ccp_up,                     /* Called when fsm reaches OPENED state */
154*7c478bd9Sstevel@tonic-gate     ccp_down,                   /* Called when fsm leaves OPENED state */
155*7c478bd9Sstevel@tonic-gate     NULL,                       /* Called when we want the lower layer up */
156*7c478bd9Sstevel@tonic-gate     NULL,                       /* Called when we want the lower layer down */
157*7c478bd9Sstevel@tonic-gate     NULL,			/* Retransmission is necessary */
158*7c478bd9Sstevel@tonic-gate     ccp_extcode,                /* Called to handle LCP-specific codes */
159*7c478bd9Sstevel@tonic-gate     "CCP",			/* String name of protocol */
160*7c478bd9Sstevel@tonic-gate     ccp_codereject,             /* Peer rejected a code number */
161*7c478bd9Sstevel@tonic-gate };
162*7c478bd9Sstevel@tonic-gate 
163*7c478bd9Sstevel@tonic-gate /*
164*7c478bd9Sstevel@tonic-gate  * Local statics.
165*7c478bd9Sstevel@tonic-gate  */
166*7c478bd9Sstevel@tonic-gate static void ccp_rack_timeout __P((void *));
167*7c478bd9Sstevel@tonic-gate static char * method_name __P((ccp_options *, ccp_options *));
168*7c478bd9Sstevel@tonic-gate 
169*7c478bd9Sstevel@tonic-gate /*
170*7c478bd9Sstevel@tonic-gate  * Do we want / did we get any compression?
171*7c478bd9Sstevel@tonic-gate  */
172*7c478bd9Sstevel@tonic-gate #define ANY_COMPRESS(opt)	((opt).deflate || (opt).bsd_compress \
173*7c478bd9Sstevel@tonic-gate 				 || (opt).predictor_1 || (opt).predictor_2)
174*7c478bd9Sstevel@tonic-gate 
175*7c478bd9Sstevel@tonic-gate /*
176*7c478bd9Sstevel@tonic-gate  * Local state (mainly for handling reset-reqs and reset-acks).
177*7c478bd9Sstevel@tonic-gate  */
178*7c478bd9Sstevel@tonic-gate static int ccp_localstate[NUM_PPP];
179*7c478bd9Sstevel@tonic-gate #define RACK_PENDING	0x0001	/* waiting for reset-ack */
180*7c478bd9Sstevel@tonic-gate #define RREQ_REPEAT	0x0002	/* send another reset-req if no reset-ack */
181*7c478bd9Sstevel@tonic-gate #define RREQ_REJECTED	0x0004	/* peer code-rejected reset-request */
182*7c478bd9Sstevel@tonic-gate #define RACK_REJECTED	0x0008	/* peer code-rejected reset-ack */
183*7c478bd9Sstevel@tonic-gate #define RREQ_IGNORED	0x0010	/* peer just ignored reset-request */
184*7c478bd9Sstevel@tonic-gate 
185*7c478bd9Sstevel@tonic-gate #define RACKTIMEOUT	1	/* time in seconds between Reset-Requests */
186*7c478bd9Sstevel@tonic-gate 
187*7c478bd9Sstevel@tonic-gate static int all_rejected[NUM_PPP];	/* we rejected all peer's options */
188*7c478bd9Sstevel@tonic-gate 
189*7c478bd9Sstevel@tonic-gate #ifdef COMP_TUNE
190*7c478bd9Sstevel@tonic-gate static int deflate_tune = -1;	/* compression effort level for deflate */
191*7c478bd9Sstevel@tonic-gate #endif
192*7c478bd9Sstevel@tonic-gate static int deflate_rmax = DEFLATE_MAX_SIZE;	/* max rbits */
193*7c478bd9Sstevel@tonic-gate static int deflate_amax = DEFLATE_MAX_SIZE;	/* max abits */
194*7c478bd9Sstevel@tonic-gate 
195*7c478bd9Sstevel@tonic-gate /*
196*7c478bd9Sstevel@tonic-gate  * Option parsing.
197*7c478bd9Sstevel@tonic-gate  */
198*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
199*7c478bd9Sstevel@tonic-gate static int
200*7c478bd9Sstevel@tonic-gate setbsdcomp(argv, opt)
201*7c478bd9Sstevel@tonic-gate     char **argv;
202*7c478bd9Sstevel@tonic-gate     option_t *opt;
203*7c478bd9Sstevel@tonic-gate {
204*7c478bd9Sstevel@tonic-gate     int rbits, abits;
205*7c478bd9Sstevel@tonic-gate     char *str, *endp;
206*7c478bd9Sstevel@tonic-gate 
207*7c478bd9Sstevel@tonic-gate     str = *argv;
208*7c478bd9Sstevel@tonic-gate     abits = rbits = strtol(str, &endp, 0);
209*7c478bd9Sstevel@tonic-gate     if (endp != str && *endp == ',') {
210*7c478bd9Sstevel@tonic-gate 	str = endp + 1;
211*7c478bd9Sstevel@tonic-gate 	abits = strtol(str, &endp, 0);
212*7c478bd9Sstevel@tonic-gate     }
213*7c478bd9Sstevel@tonic-gate     if (*endp != '\0' || endp == str) {
214*7c478bd9Sstevel@tonic-gate 	option_error("invalid parameter '%s' for bsdcomp option", *argv);
215*7c478bd9Sstevel@tonic-gate 	return 0;
216*7c478bd9Sstevel@tonic-gate     }
217*7c478bd9Sstevel@tonic-gate     if ((rbits != 0 && (rbits < BSD_MIN_BITS || rbits > BSD_MAX_BITS))
218*7c478bd9Sstevel@tonic-gate 	|| (abits != 0 && (abits < BSD_MIN_BITS || abits > BSD_MAX_BITS))) {
219*7c478bd9Sstevel@tonic-gate 	option_error("bsdcomp option values must be 0 or %d .. %d",
220*7c478bd9Sstevel@tonic-gate 		     BSD_MIN_BITS, BSD_MAX_BITS);
221*7c478bd9Sstevel@tonic-gate 	return 0;
222*7c478bd9Sstevel@tonic-gate     }
223*7c478bd9Sstevel@tonic-gate     if (rbits > 0) {
224*7c478bd9Sstevel@tonic-gate 	ccp_wantoptions[0].bsd_compress = 1;
225*7c478bd9Sstevel@tonic-gate 	ccp_wantoptions[0].bsd_bits = rbits;
226*7c478bd9Sstevel@tonic-gate     } else
227*7c478bd9Sstevel@tonic-gate 	ccp_wantoptions[0].bsd_compress = 0;
228*7c478bd9Sstevel@tonic-gate     if (abits > 0) {
229*7c478bd9Sstevel@tonic-gate 	ccp_allowoptions[0].bsd_compress = 1;
230*7c478bd9Sstevel@tonic-gate 	ccp_allowoptions[0].bsd_bits = abits;
231*7c478bd9Sstevel@tonic-gate     } else
232*7c478bd9Sstevel@tonic-gate 	ccp_allowoptions[0].bsd_compress = 0;
233*7c478bd9Sstevel@tonic-gate     return 1;
234*7c478bd9Sstevel@tonic-gate }
235*7c478bd9Sstevel@tonic-gate 
236*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
237*7c478bd9Sstevel@tonic-gate static int
238*7c478bd9Sstevel@tonic-gate setdeflate(argv, opt)
239*7c478bd9Sstevel@tonic-gate     char **argv;
240*7c478bd9Sstevel@tonic-gate     option_t *opt;
241*7c478bd9Sstevel@tonic-gate {
242*7c478bd9Sstevel@tonic-gate     int rbits, abits, def_rmax, def_amax;
243*7c478bd9Sstevel@tonic-gate     char *str, *endp;
244*7c478bd9Sstevel@tonic-gate 
245*7c478bd9Sstevel@tonic-gate     str = endp = *argv;
246*7c478bd9Sstevel@tonic-gate     if (*str == ',')
247*7c478bd9Sstevel@tonic-gate 	abits = rbits = -1;
248*7c478bd9Sstevel@tonic-gate     else
249*7c478bd9Sstevel@tonic-gate 	abits = rbits = strtol(str, &endp, 0);
250*7c478bd9Sstevel@tonic-gate     if (*endp == ',') {
251*7c478bd9Sstevel@tonic-gate 	str = ++endp;
252*7c478bd9Sstevel@tonic-gate 	if (*str == ',')
253*7c478bd9Sstevel@tonic-gate 	    abits = rbits;
254*7c478bd9Sstevel@tonic-gate 	else
255*7c478bd9Sstevel@tonic-gate 	    abits = strtol(str, &endp, 0);
256*7c478bd9Sstevel@tonic-gate     }
257*7c478bd9Sstevel@tonic-gate #ifdef COMP_TUNE
258*7c478bd9Sstevel@tonic-gate     if (*endp == ',' && privileged_option) {
259*7c478bd9Sstevel@tonic-gate 	str = ++endp;
260*7c478bd9Sstevel@tonic-gate 	deflate_tune = strtol(str, &endp, 0);
261*7c478bd9Sstevel@tonic-gate     }
262*7c478bd9Sstevel@tonic-gate #endif
263*7c478bd9Sstevel@tonic-gate     if (*endp != '\0' || endp == str) {
264*7c478bd9Sstevel@tonic-gate 	option_error("invalid parameter '%s' for deflate option", *argv);
265*7c478bd9Sstevel@tonic-gate 	return 0;
266*7c478bd9Sstevel@tonic-gate     }
267*7c478bd9Sstevel@tonic-gate     if (privileged_option) {
268*7c478bd9Sstevel@tonic-gate 	def_rmax = def_amax = DEFLATE_MAX_SIZE;
269*7c478bd9Sstevel@tonic-gate     } else {
270*7c478bd9Sstevel@tonic-gate 	def_rmax = deflate_rmax;
271*7c478bd9Sstevel@tonic-gate 	def_amax = deflate_amax;
272*7c478bd9Sstevel@tonic-gate     }
273*7c478bd9Sstevel@tonic-gate     if (rbits < 0)
274*7c478bd9Sstevel@tonic-gate 	rbits = def_rmax;
275*7c478bd9Sstevel@tonic-gate     if (abits < 0)
276*7c478bd9Sstevel@tonic-gate 	abits = def_amax;
277*7c478bd9Sstevel@tonic-gate     if ((rbits != 0 && (rbits <= DEFLATE_MIN_SIZE || rbits > def_rmax))
278*7c478bd9Sstevel@tonic-gate 	|| (abits != 0 && (abits <= DEFLATE_MIN_SIZE || abits > def_amax))) {
279*7c478bd9Sstevel@tonic-gate 	option_error("deflate option values must be 0 or {%d,%d} .. {%d,%d}",
280*7c478bd9Sstevel@tonic-gate 		     DEFLATE_MIN_SIZE+1, DEFLATE_MIN_SIZE+1,
281*7c478bd9Sstevel@tonic-gate 		     def_rmax, def_amax);
282*7c478bd9Sstevel@tonic-gate 	return 0;
283*7c478bd9Sstevel@tonic-gate     }
284*7c478bd9Sstevel@tonic-gate     if (privileged_option) {
285*7c478bd9Sstevel@tonic-gate 	deflate_rmax = rbits;
286*7c478bd9Sstevel@tonic-gate 	deflate_amax = abits;
287*7c478bd9Sstevel@tonic-gate     }
288*7c478bd9Sstevel@tonic-gate     if (rbits > 0) {
289*7c478bd9Sstevel@tonic-gate 	ccp_wantoptions[0].deflate = 1;
290*7c478bd9Sstevel@tonic-gate 	ccp_wantoptions[0].deflate_size = rbits;
291*7c478bd9Sstevel@tonic-gate     } else
292*7c478bd9Sstevel@tonic-gate 	ccp_wantoptions[0].deflate = 0;
293*7c478bd9Sstevel@tonic-gate     if (abits > 0) {
294*7c478bd9Sstevel@tonic-gate 	ccp_allowoptions[0].deflate = 1;
295*7c478bd9Sstevel@tonic-gate 	ccp_allowoptions[0].deflate_size = abits;
296*7c478bd9Sstevel@tonic-gate     } else
297*7c478bd9Sstevel@tonic-gate 	ccp_allowoptions[0].deflate = 0;
298*7c478bd9Sstevel@tonic-gate     return 1;
299*7c478bd9Sstevel@tonic-gate }
300*7c478bd9Sstevel@tonic-gate 
301*7c478bd9Sstevel@tonic-gate 
302*7c478bd9Sstevel@tonic-gate /*
303*7c478bd9Sstevel@tonic-gate  * ccp_init - initialize CCP.
304*7c478bd9Sstevel@tonic-gate  */
305*7c478bd9Sstevel@tonic-gate static void
306*7c478bd9Sstevel@tonic-gate ccp_init(unit)
307*7c478bd9Sstevel@tonic-gate     int unit;
308*7c478bd9Sstevel@tonic-gate {
309*7c478bd9Sstevel@tonic-gate     fsm *f = &ccp_fsm[unit];
310*7c478bd9Sstevel@tonic-gate 
311*7c478bd9Sstevel@tonic-gate     f->unit = unit;
312*7c478bd9Sstevel@tonic-gate     f->protocol = PPP_CCP;
313*7c478bd9Sstevel@tonic-gate     f->callbacks = &ccp_callbacks;
314*7c478bd9Sstevel@tonic-gate     fsm_init(f);
315*7c478bd9Sstevel@tonic-gate     f->flags |= OPT_RESTART;
316*7c478bd9Sstevel@tonic-gate 
317*7c478bd9Sstevel@tonic-gate     BZERO(&ccp_wantoptions[unit],  sizeof(ccp_options));
318*7c478bd9Sstevel@tonic-gate     BZERO(&ccp_gotoptions[unit],   sizeof(ccp_options));
319*7c478bd9Sstevel@tonic-gate     BZERO(&ccp_allowoptions[unit], sizeof(ccp_options));
320*7c478bd9Sstevel@tonic-gate     BZERO(&ccp_hisoptions[unit],   sizeof(ccp_options));
321*7c478bd9Sstevel@tonic-gate 
322*7c478bd9Sstevel@tonic-gate     ccp_wantoptions[0].deflate = 1;
323*7c478bd9Sstevel@tonic-gate     ccp_wantoptions[0].deflate_size = DEFLATE_MAX_SIZE;
324*7c478bd9Sstevel@tonic-gate     ccp_wantoptions[0].deflate_correct = 1;
325*7c478bd9Sstevel@tonic-gate     ccp_wantoptions[0].deflate_draft = 1;
326*7c478bd9Sstevel@tonic-gate     ccp_allowoptions[0].deflate = 1;
327*7c478bd9Sstevel@tonic-gate     ccp_allowoptions[0].deflate_size = DEFLATE_MAX_SIZE;
328*7c478bd9Sstevel@tonic-gate     ccp_allowoptions[0].deflate_correct = 1;
329*7c478bd9Sstevel@tonic-gate     ccp_allowoptions[0].deflate_draft = 1;
330*7c478bd9Sstevel@tonic-gate 
331*7c478bd9Sstevel@tonic-gate     ccp_wantoptions[0].bsd_compress = 1;
332*7c478bd9Sstevel@tonic-gate     ccp_wantoptions[0].bsd_bits = BSD_MAX_BITS;
333*7c478bd9Sstevel@tonic-gate     ccp_allowoptions[0].bsd_compress = 1;
334*7c478bd9Sstevel@tonic-gate     ccp_allowoptions[0].bsd_bits = BSD_MAX_BITS;
335*7c478bd9Sstevel@tonic-gate 
336*7c478bd9Sstevel@tonic-gate     ccp_allowoptions[0].predictor_1 = 1;
337*7c478bd9Sstevel@tonic-gate }
338*7c478bd9Sstevel@tonic-gate 
339*7c478bd9Sstevel@tonic-gate /*
340*7c478bd9Sstevel@tonic-gate  * ccp_open - CCP is allowed to come up.
341*7c478bd9Sstevel@tonic-gate  */
342*7c478bd9Sstevel@tonic-gate static void
343*7c478bd9Sstevel@tonic-gate ccp_open(unit)
344*7c478bd9Sstevel@tonic-gate     int unit;
345*7c478bd9Sstevel@tonic-gate {
346*7c478bd9Sstevel@tonic-gate     fsm *f = &ccp_fsm[unit];
347*7c478bd9Sstevel@tonic-gate 
348*7c478bd9Sstevel@tonic-gate     /*
349*7c478bd9Sstevel@tonic-gate      * If we haven't gone open yet (first time through), then go open
350*7c478bd9Sstevel@tonic-gate      * but not up.  Otherwise, skip this to allow reopen to reset the
351*7c478bd9Sstevel@tonic-gate      * compressor.
352*7c478bd9Sstevel@tonic-gate      */
353*7c478bd9Sstevel@tonic-gate     if (f->state != OPENED)
354*7c478bd9Sstevel@tonic-gate 	ccp_flags_set(unit, 1, 0);
355*7c478bd9Sstevel@tonic-gate 
356*7c478bd9Sstevel@tonic-gate     /*
357*7c478bd9Sstevel@tonic-gate      * Find out which compressors the kernel supports before
358*7c478bd9Sstevel@tonic-gate      * deciding whether to open in silent mode.
359*7c478bd9Sstevel@tonic-gate      */
360*7c478bd9Sstevel@tonic-gate     ccp_resetci(f);
361*7c478bd9Sstevel@tonic-gate     if (!ANY_COMPRESS(ccp_gotoptions[unit]))
362*7c478bd9Sstevel@tonic-gate 	f->flags |= OPT_SILENT;
363*7c478bd9Sstevel@tonic-gate 
364*7c478bd9Sstevel@tonic-gate     fsm_open(f);
365*7c478bd9Sstevel@tonic-gate }
366*7c478bd9Sstevel@tonic-gate 
367*7c478bd9Sstevel@tonic-gate /*
368*7c478bd9Sstevel@tonic-gate  * ccp_close - Terminate CCP.
369*7c478bd9Sstevel@tonic-gate  */
370*7c478bd9Sstevel@tonic-gate static void
371*7c478bd9Sstevel@tonic-gate ccp_close(unit, reason)
372*7c478bd9Sstevel@tonic-gate     int unit;
373*7c478bd9Sstevel@tonic-gate     char *reason;
374*7c478bd9Sstevel@tonic-gate {
375*7c478bd9Sstevel@tonic-gate     ccp_flags_set(unit, 0, 0);
376*7c478bd9Sstevel@tonic-gate     fsm_close(&ccp_fsm[unit], reason);
377*7c478bd9Sstevel@tonic-gate }
378*7c478bd9Sstevel@tonic-gate 
379*7c478bd9Sstevel@tonic-gate /*
380*7c478bd9Sstevel@tonic-gate  * ccp_lowerup - we may now transmit CCP packets.
381*7c478bd9Sstevel@tonic-gate  */
382*7c478bd9Sstevel@tonic-gate static void
383*7c478bd9Sstevel@tonic-gate ccp_lowerup(unit)
384*7c478bd9Sstevel@tonic-gate     int unit;
385*7c478bd9Sstevel@tonic-gate {
386*7c478bd9Sstevel@tonic-gate     fsm_lowerup(&ccp_fsm[unit]);
387*7c478bd9Sstevel@tonic-gate }
388*7c478bd9Sstevel@tonic-gate 
389*7c478bd9Sstevel@tonic-gate /*
390*7c478bd9Sstevel@tonic-gate  * ccp_lowerdown - we may not transmit CCP packets.
391*7c478bd9Sstevel@tonic-gate  */
392*7c478bd9Sstevel@tonic-gate static void
393*7c478bd9Sstevel@tonic-gate ccp_lowerdown(unit)
394*7c478bd9Sstevel@tonic-gate     int unit;
395*7c478bd9Sstevel@tonic-gate {
396*7c478bd9Sstevel@tonic-gate     fsm_lowerdown(&ccp_fsm[unit]);
397*7c478bd9Sstevel@tonic-gate }
398*7c478bd9Sstevel@tonic-gate 
399*7c478bd9Sstevel@tonic-gate /*
400*7c478bd9Sstevel@tonic-gate  * ccp_input - process a received CCP packet.
401*7c478bd9Sstevel@tonic-gate  */
402*7c478bd9Sstevel@tonic-gate static void
403*7c478bd9Sstevel@tonic-gate ccp_input(unit, p, len)
404*7c478bd9Sstevel@tonic-gate     int unit;
405*7c478bd9Sstevel@tonic-gate     u_char *p;
406*7c478bd9Sstevel@tonic-gate     int len;
407*7c478bd9Sstevel@tonic-gate {
408*7c478bd9Sstevel@tonic-gate     fsm *f = &ccp_fsm[unit];
409*7c478bd9Sstevel@tonic-gate     int oldstate;
410*7c478bd9Sstevel@tonic-gate 
411*7c478bd9Sstevel@tonic-gate     /*
412*7c478bd9Sstevel@tonic-gate      * Check for a terminate-request so we can print a message.
413*7c478bd9Sstevel@tonic-gate      */
414*7c478bd9Sstevel@tonic-gate     oldstate = f->state;
415*7c478bd9Sstevel@tonic-gate     fsm_input(f, p, len);
416*7c478bd9Sstevel@tonic-gate     if (oldstate == OPENED && p[0] == CODE_TERMREQ && f->state != OPENED)
417*7c478bd9Sstevel@tonic-gate 	notice("Compression disabled by peer.");
418*7c478bd9Sstevel@tonic-gate 
419*7c478bd9Sstevel@tonic-gate     /*
420*7c478bd9Sstevel@tonic-gate      * If we get a terminate-ack and we're not asking for compression,
421*7c478bd9Sstevel@tonic-gate      * close CCP.  (Terminate-Request is handled by fsm_input() above.)
422*7c478bd9Sstevel@tonic-gate      */
423*7c478bd9Sstevel@tonic-gate     if (oldstate == REQSENT && p[0] == CODE_TERMACK
424*7c478bd9Sstevel@tonic-gate 	&& !ANY_COMPRESS(ccp_gotoptions[unit]))
425*7c478bd9Sstevel@tonic-gate 	ccp_close(unit, "No compression negotiated");
426*7c478bd9Sstevel@tonic-gate }
427*7c478bd9Sstevel@tonic-gate 
428*7c478bd9Sstevel@tonic-gate /*
429*7c478bd9Sstevel@tonic-gate  * Handle a CCP-specific code.
430*7c478bd9Sstevel@tonic-gate  */
431*7c478bd9Sstevel@tonic-gate static int
432*7c478bd9Sstevel@tonic-gate ccp_extcode(f, code, id, p, len)
433*7c478bd9Sstevel@tonic-gate     fsm *f;
434*7c478bd9Sstevel@tonic-gate     int code, id;
435*7c478bd9Sstevel@tonic-gate     u_char *p;
436*7c478bd9Sstevel@tonic-gate     int len;
437*7c478bd9Sstevel@tonic-gate {
438*7c478bd9Sstevel@tonic-gate     switch (code) {
439*7c478bd9Sstevel@tonic-gate     case CCP_RESETREQ:
440*7c478bd9Sstevel@tonic-gate 	/* If not open, then silently ignore. */
441*7c478bd9Sstevel@tonic-gate 	if (f->state != OPENED)
442*7c478bd9Sstevel@tonic-gate 	    break;
443*7c478bd9Sstevel@tonic-gate 	/* send a reset-ack, which our transmitter module will see and
444*7c478bd9Sstevel@tonic-gate 	   reset its compression state. */
445*7c478bd9Sstevel@tonic-gate 	fsm_sdata(f, CCP_RESETACK, id, p, len);
446*7c478bd9Sstevel@tonic-gate 	break;
447*7c478bd9Sstevel@tonic-gate 
448*7c478bd9Sstevel@tonic-gate     case CCP_RESETACK:
449*7c478bd9Sstevel@tonic-gate 	/*
450*7c478bd9Sstevel@tonic-gate 	 * Note that the compression module isn't picky about ID
451*7c478bd9Sstevel@tonic-gate 	 * numbers and such.
452*7c478bd9Sstevel@tonic-gate 	 */
453*7c478bd9Sstevel@tonic-gate 	ccp_localstate[f->unit] &= ~RREQ_IGNORED & ~RREQ_REJECTED;
454*7c478bd9Sstevel@tonic-gate 	if ((ccp_localstate[f->unit] & RACK_PENDING) && id == f->reqid) {
455*7c478bd9Sstevel@tonic-gate 	    ccp_localstate[f->unit] &= ~RACK_PENDING & ~RREQ_REPEAT;
456*7c478bd9Sstevel@tonic-gate 	    UNTIMEOUT(ccp_rack_timeout, f);
457*7c478bd9Sstevel@tonic-gate 	}
458*7c478bd9Sstevel@tonic-gate 	break;
459*7c478bd9Sstevel@tonic-gate 
460*7c478bd9Sstevel@tonic-gate     default:
461*7c478bd9Sstevel@tonic-gate 	/* Tell fsm to send code reject */
462*7c478bd9Sstevel@tonic-gate 	return (0);
463*7c478bd9Sstevel@tonic-gate     }
464*7c478bd9Sstevel@tonic-gate 
465*7c478bd9Sstevel@tonic-gate     return (1);
466*7c478bd9Sstevel@tonic-gate }
467*7c478bd9Sstevel@tonic-gate 
468*7c478bd9Sstevel@tonic-gate /*
469*7c478bd9Sstevel@tonic-gate  * Handle Code-Reject for one of our extended codes by dropping back to
470*7c478bd9Sstevel@tonic-gate  * reopen as mechanism to restart compression.
471*7c478bd9Sstevel@tonic-gate  */
472*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
473*7c478bd9Sstevel@tonic-gate static int
474*7c478bd9Sstevel@tonic-gate ccp_codereject(f, code, id, inp, len)
475*7c478bd9Sstevel@tonic-gate     fsm *f;
476*7c478bd9Sstevel@tonic-gate     int code, id;
477*7c478bd9Sstevel@tonic-gate     u_char *inp;
478*7c478bd9Sstevel@tonic-gate     int len;
479*7c478bd9Sstevel@tonic-gate {
480*7c478bd9Sstevel@tonic-gate     switch (code) {
481*7c478bd9Sstevel@tonic-gate     case CCP_RESETREQ:
482*7c478bd9Sstevel@tonic-gate 	if (!(ccp_localstate[f->unit] & RREQ_REJECTED)) {
483*7c478bd9Sstevel@tonic-gate 	    info("peer has rejected CCP Reset-Request; falling back on Open");
484*7c478bd9Sstevel@tonic-gate 	    if (f->state == OPENED)
485*7c478bd9Sstevel@tonic-gate 		ccp_open(f->unit);
486*7c478bd9Sstevel@tonic-gate 	}
487*7c478bd9Sstevel@tonic-gate 	ccp_localstate[f->unit] |= RREQ_REJECTED;
488*7c478bd9Sstevel@tonic-gate 	return (0);
489*7c478bd9Sstevel@tonic-gate 
490*7c478bd9Sstevel@tonic-gate     case CCP_RESETACK:
491*7c478bd9Sstevel@tonic-gate 	/*
492*7c478bd9Sstevel@tonic-gate 	 * Peer must have sent us CCP Reset-Request but then code-rejected
493*7c478bd9Sstevel@tonic-gate 	 * when we sent CCP Reset-Ack.  He's a moron, be we have to obey
494*7c478bd9Sstevel@tonic-gate 	 * his wishes.
495*7c478bd9Sstevel@tonic-gate 	 */
496*7c478bd9Sstevel@tonic-gate 	ccp_localstate[f->unit] |= RACK_REJECTED;
497*7c478bd9Sstevel@tonic-gate 	notice("peer has erroneously rejected CCP Reset-Ack");
498*7c478bd9Sstevel@tonic-gate 	f->term_reason = "peer sent Code-Reject for CCP Reset-Ack";
499*7c478bd9Sstevel@tonic-gate 	f->term_reason_len = strlen(f->term_reason);
500*7c478bd9Sstevel@tonic-gate 	break;
501*7c478bd9Sstevel@tonic-gate 
502*7c478bd9Sstevel@tonic-gate     default:
503*7c478bd9Sstevel@tonic-gate 	f->term_reason = "peer sent invalid Code-Reject";
504*7c478bd9Sstevel@tonic-gate 	break;
505*7c478bd9Sstevel@tonic-gate     }
506*7c478bd9Sstevel@tonic-gate 
507*7c478bd9Sstevel@tonic-gate     f->term_reason_len = strlen(f->term_reason);
508*7c478bd9Sstevel@tonic-gate     return (1);
509*7c478bd9Sstevel@tonic-gate }
510*7c478bd9Sstevel@tonic-gate 
511*7c478bd9Sstevel@tonic-gate /*
512*7c478bd9Sstevel@tonic-gate  * ccp_protrej - peer doesn't talk CCP.
513*7c478bd9Sstevel@tonic-gate  */
514*7c478bd9Sstevel@tonic-gate static void
515*7c478bd9Sstevel@tonic-gate ccp_protrej(unit)
516*7c478bd9Sstevel@tonic-gate     int unit;
517*7c478bd9Sstevel@tonic-gate {
518*7c478bd9Sstevel@tonic-gate     /* Neither open nor up. */
519*7c478bd9Sstevel@tonic-gate     ccp_flags_set(unit, 0, 0);
520*7c478bd9Sstevel@tonic-gate     fsm_lowerdown(&ccp_fsm[unit]);
521*7c478bd9Sstevel@tonic-gate }
522*7c478bd9Sstevel@tonic-gate 
523*7c478bd9Sstevel@tonic-gate /*
524*7c478bd9Sstevel@tonic-gate  * ccp_resetci - initialize at start of negotiation.
525*7c478bd9Sstevel@tonic-gate  */
526*7c478bd9Sstevel@tonic-gate static void
527*7c478bd9Sstevel@tonic-gate ccp_resetci(f)
528*7c478bd9Sstevel@tonic-gate     fsm *f;
529*7c478bd9Sstevel@tonic-gate {
530*7c478bd9Sstevel@tonic-gate     ccp_options *go = &ccp_gotoptions[f->unit];
531*7c478bd9Sstevel@tonic-gate     u_char opt_buf[16];
532*7c478bd9Sstevel@tonic-gate 
533*7c478bd9Sstevel@tonic-gate     *go = ccp_wantoptions[f->unit];
534*7c478bd9Sstevel@tonic-gate     all_rejected[f->unit] = 0;
535*7c478bd9Sstevel@tonic-gate 
536*7c478bd9Sstevel@tonic-gate     /*
537*7c478bd9Sstevel@tonic-gate      * Check whether the kernel knows about the various
538*7c478bd9Sstevel@tonic-gate      * decompression methods we might request.
539*7c478bd9Sstevel@tonic-gate      */
540*7c478bd9Sstevel@tonic-gate     if (go->bsd_compress) {
541*7c478bd9Sstevel@tonic-gate 	opt_buf[0] = CI_BSD_COMPRESS;
542*7c478bd9Sstevel@tonic-gate 	opt_buf[1] = CILEN_BSD_COMPRESS;
543*7c478bd9Sstevel@tonic-gate 	opt_buf[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, BSD_MIN_BITS);
544*7c478bd9Sstevel@tonic-gate 	if (ccp_test(f->unit, opt_buf, CILEN_BSD_COMPRESS, 0) <= 0)
545*7c478bd9Sstevel@tonic-gate 	    go->bsd_compress = 0;
546*7c478bd9Sstevel@tonic-gate     }
547*7c478bd9Sstevel@tonic-gate     if (go->deflate) {
548*7c478bd9Sstevel@tonic-gate 	if (go->deflate_correct) {
549*7c478bd9Sstevel@tonic-gate 	    opt_buf[0] = CI_DEFLATE;
550*7c478bd9Sstevel@tonic-gate 	    opt_buf[1] = CILEN_DEFLATE;
551*7c478bd9Sstevel@tonic-gate 	    opt_buf[2] = DEFLATE_MAKE_OPT(DEFLATE_MIN_SIZE+1);
552*7c478bd9Sstevel@tonic-gate 	    opt_buf[3] = DEFLATE_CHK_SEQUENCE;
553*7c478bd9Sstevel@tonic-gate 	    if (ccp_test(f->unit, opt_buf, CILEN_DEFLATE, 0) <= 0)
554*7c478bd9Sstevel@tonic-gate 		go->deflate_correct = 0;
555*7c478bd9Sstevel@tonic-gate 	}
556*7c478bd9Sstevel@tonic-gate 	if (go->deflate_draft) {
557*7c478bd9Sstevel@tonic-gate 	    opt_buf[0] = CI_DEFLATE_DRAFT;
558*7c478bd9Sstevel@tonic-gate 	    opt_buf[1] = CILEN_DEFLATE;
559*7c478bd9Sstevel@tonic-gate 	    opt_buf[2] = DEFLATE_MAKE_OPT(DEFLATE_MIN_SIZE+1);
560*7c478bd9Sstevel@tonic-gate 	    opt_buf[3] = DEFLATE_CHK_SEQUENCE;
561*7c478bd9Sstevel@tonic-gate 	    if (ccp_test(f->unit, opt_buf, CILEN_DEFLATE, 0) <= 0)
562*7c478bd9Sstevel@tonic-gate 		go->deflate_draft = 0;
563*7c478bd9Sstevel@tonic-gate 	}
564*7c478bd9Sstevel@tonic-gate 	if (!go->deflate_correct && !go->deflate_draft)
565*7c478bd9Sstevel@tonic-gate 	    go->deflate = 0;
566*7c478bd9Sstevel@tonic-gate     }
567*7c478bd9Sstevel@tonic-gate     if (go->predictor_1) {
568*7c478bd9Sstevel@tonic-gate 	opt_buf[0] = CI_PREDICTOR_1;
569*7c478bd9Sstevel@tonic-gate 	opt_buf[1] = CILEN_PREDICTOR_1;
570*7c478bd9Sstevel@tonic-gate 	if (ccp_test(f->unit, opt_buf, CILEN_PREDICTOR_1, 0) <= 0)
571*7c478bd9Sstevel@tonic-gate 	    go->predictor_1 = 0;
572*7c478bd9Sstevel@tonic-gate     }
573*7c478bd9Sstevel@tonic-gate     if (go->predictor_2) {
574*7c478bd9Sstevel@tonic-gate 	opt_buf[0] = CI_PREDICTOR_2;
575*7c478bd9Sstevel@tonic-gate 	opt_buf[1] = CILEN_PREDICTOR_2;
576*7c478bd9Sstevel@tonic-gate 	if (ccp_test(f->unit, opt_buf, CILEN_PREDICTOR_2, 0) <= 0)
577*7c478bd9Sstevel@tonic-gate 	    go->predictor_2 = 0;
578*7c478bd9Sstevel@tonic-gate     }
579*7c478bd9Sstevel@tonic-gate }
580*7c478bd9Sstevel@tonic-gate 
581*7c478bd9Sstevel@tonic-gate /*
582*7c478bd9Sstevel@tonic-gate  * ccp_cilen - Return total length of our configuration info.
583*7c478bd9Sstevel@tonic-gate  */
584*7c478bd9Sstevel@tonic-gate static int
585*7c478bd9Sstevel@tonic-gate ccp_cilen(f)
586*7c478bd9Sstevel@tonic-gate     fsm *f;
587*7c478bd9Sstevel@tonic-gate {
588*7c478bd9Sstevel@tonic-gate     ccp_options *go = &ccp_gotoptions[f->unit];
589*7c478bd9Sstevel@tonic-gate 
590*7c478bd9Sstevel@tonic-gate     return (go->bsd_compress? CILEN_BSD_COMPRESS: 0)
591*7c478bd9Sstevel@tonic-gate 	+ (go->deflate && go->deflate_correct ? CILEN_DEFLATE : 0)
592*7c478bd9Sstevel@tonic-gate 	+ (go->deflate && go->deflate_draft ? CILEN_DEFLATE : 0)
593*7c478bd9Sstevel@tonic-gate 	+ (go->predictor_1? CILEN_PREDICTOR_1: 0)
594*7c478bd9Sstevel@tonic-gate 	+ (go->predictor_2? CILEN_PREDICTOR_2: 0);
595*7c478bd9Sstevel@tonic-gate }
596*7c478bd9Sstevel@tonic-gate 
597*7c478bd9Sstevel@tonic-gate /*
598*7c478bd9Sstevel@tonic-gate  * ccp_addci - put our requests in a packet.
599*7c478bd9Sstevel@tonic-gate  */
600*7c478bd9Sstevel@tonic-gate static void
601*7c478bd9Sstevel@tonic-gate ccp_addci(f, p, lenp)
602*7c478bd9Sstevel@tonic-gate     fsm *f;
603*7c478bd9Sstevel@tonic-gate     u_char *p;
604*7c478bd9Sstevel@tonic-gate     int *lenp;
605*7c478bd9Sstevel@tonic-gate {
606*7c478bd9Sstevel@tonic-gate     int res;
607*7c478bd9Sstevel@tonic-gate     ccp_options *go = &ccp_gotoptions[f->unit];
608*7c478bd9Sstevel@tonic-gate     u_char *p0 = p;
609*7c478bd9Sstevel@tonic-gate 
610*7c478bd9Sstevel@tonic-gate     /*
611*7c478bd9Sstevel@tonic-gate      * Add the compression types that we can receive, in decreasing
612*7c478bd9Sstevel@tonic-gate      * preference order.  Get the kernel to allocate the first one
613*7c478bd9Sstevel@tonic-gate      * in case it gets Acked.
614*7c478bd9Sstevel@tonic-gate      */
615*7c478bd9Sstevel@tonic-gate     if (go->deflate) {
616*7c478bd9Sstevel@tonic-gate 	p[0] = go->deflate_correct? CI_DEFLATE: CI_DEFLATE_DRAFT;
617*7c478bd9Sstevel@tonic-gate 	p[1] = CILEN_DEFLATE;
618*7c478bd9Sstevel@tonic-gate 	p[2] = DEFLATE_MAKE_OPT(go->deflate_size);
619*7c478bd9Sstevel@tonic-gate 	p[3] = DEFLATE_CHK_SEQUENCE;
620*7c478bd9Sstevel@tonic-gate 	for (;;) {
621*7c478bd9Sstevel@tonic-gate 	    res = ccp_test(f->unit, p, CILEN_DEFLATE, 0);
622*7c478bd9Sstevel@tonic-gate 	    if (res > 0) {
623*7c478bd9Sstevel@tonic-gate 		p += CILEN_DEFLATE;
624*7c478bd9Sstevel@tonic-gate 		break;
625*7c478bd9Sstevel@tonic-gate 	    }
626*7c478bd9Sstevel@tonic-gate 	    if (res < 0 || go->deflate_size <= DEFLATE_MIN_SIZE+1) {
627*7c478bd9Sstevel@tonic-gate 		go->deflate = 0;
628*7c478bd9Sstevel@tonic-gate 		break;
629*7c478bd9Sstevel@tonic-gate 	    }
630*7c478bd9Sstevel@tonic-gate 	    --go->deflate_size;
631*7c478bd9Sstevel@tonic-gate 	    p[2] = DEFLATE_MAKE_OPT(go->deflate_size);
632*7c478bd9Sstevel@tonic-gate 	}
633*7c478bd9Sstevel@tonic-gate 	/* If we're offering both, then this is second. */
634*7c478bd9Sstevel@tonic-gate 	if (p != p0 && go->deflate_correct && go->deflate_draft) {
635*7c478bd9Sstevel@tonic-gate 	    p[0] = CI_DEFLATE_DRAFT;
636*7c478bd9Sstevel@tonic-gate 	    p[1] = CILEN_DEFLATE;
637*7c478bd9Sstevel@tonic-gate 	    p[2] = p[2 - CILEN_DEFLATE];
638*7c478bd9Sstevel@tonic-gate 	    p[3] = DEFLATE_CHK_SEQUENCE;
639*7c478bd9Sstevel@tonic-gate 	    p += CILEN_DEFLATE;
640*7c478bd9Sstevel@tonic-gate 	}
641*7c478bd9Sstevel@tonic-gate     }
642*7c478bd9Sstevel@tonic-gate     if (go->bsd_compress) {
643*7c478bd9Sstevel@tonic-gate 	p[0] = CI_BSD_COMPRESS;
644*7c478bd9Sstevel@tonic-gate 	p[1] = CILEN_BSD_COMPRESS;
645*7c478bd9Sstevel@tonic-gate 	p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits);
646*7c478bd9Sstevel@tonic-gate 	if (p != p0) {
647*7c478bd9Sstevel@tonic-gate 	    p += CILEN_BSD_COMPRESS;	/* not the first option */
648*7c478bd9Sstevel@tonic-gate 	} else {
649*7c478bd9Sstevel@tonic-gate 	    for (;;) {
650*7c478bd9Sstevel@tonic-gate 		res = ccp_test(f->unit, p, CILEN_BSD_COMPRESS, 0);
651*7c478bd9Sstevel@tonic-gate 		if (res > 0) {
652*7c478bd9Sstevel@tonic-gate 		    p += CILEN_BSD_COMPRESS;
653*7c478bd9Sstevel@tonic-gate 		    break;
654*7c478bd9Sstevel@tonic-gate 		}
655*7c478bd9Sstevel@tonic-gate 		if (res < 0 || go->bsd_bits <= BSD_MIN_BITS) {
656*7c478bd9Sstevel@tonic-gate 		    go->bsd_compress = 0;
657*7c478bd9Sstevel@tonic-gate 		    break;
658*7c478bd9Sstevel@tonic-gate 		}
659*7c478bd9Sstevel@tonic-gate 		--go->bsd_bits;
660*7c478bd9Sstevel@tonic-gate 		p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits);
661*7c478bd9Sstevel@tonic-gate 	    }
662*7c478bd9Sstevel@tonic-gate 	}
663*7c478bd9Sstevel@tonic-gate     }
664*7c478bd9Sstevel@tonic-gate     /*
665*7c478bd9Sstevel@tonic-gate      * Prefer Predictor-1 over Predictor-2.  (The latter requires the use
666*7c478bd9Sstevel@tonic-gate      * of LAP-B and has no known implementations.)
667*7c478bd9Sstevel@tonic-gate      */
668*7c478bd9Sstevel@tonic-gate     if (go->predictor_1) {
669*7c478bd9Sstevel@tonic-gate 	p[0] = CI_PREDICTOR_1;
670*7c478bd9Sstevel@tonic-gate 	p[1] = CILEN_PREDICTOR_1;
671*7c478bd9Sstevel@tonic-gate 	if (p == p0 && ccp_test(f->unit, p, CILEN_PREDICTOR_1, 0) <= 0) {
672*7c478bd9Sstevel@tonic-gate 	    go->predictor_1 = 0;
673*7c478bd9Sstevel@tonic-gate 	} else {
674*7c478bd9Sstevel@tonic-gate 	    p += CILEN_PREDICTOR_1;
675*7c478bd9Sstevel@tonic-gate 	}
676*7c478bd9Sstevel@tonic-gate     }
677*7c478bd9Sstevel@tonic-gate     if (go->predictor_2) {
678*7c478bd9Sstevel@tonic-gate 	p[0] = CI_PREDICTOR_2;
679*7c478bd9Sstevel@tonic-gate 	p[1] = CILEN_PREDICTOR_2;
680*7c478bd9Sstevel@tonic-gate 	if (p == p0 && ccp_test(f->unit, p, CILEN_PREDICTOR_2, 0) <= 0) {
681*7c478bd9Sstevel@tonic-gate 	    go->predictor_2 = 0;
682*7c478bd9Sstevel@tonic-gate 	} else {
683*7c478bd9Sstevel@tonic-gate 	    p += CILEN_PREDICTOR_2;
684*7c478bd9Sstevel@tonic-gate 	}
685*7c478bd9Sstevel@tonic-gate     }
686*7c478bd9Sstevel@tonic-gate 
687*7c478bd9Sstevel@tonic-gate     go->method = (p > p0)? p0[0]: -1;
688*7c478bd9Sstevel@tonic-gate 
689*7c478bd9Sstevel@tonic-gate     *lenp = p - p0;
690*7c478bd9Sstevel@tonic-gate }
691*7c478bd9Sstevel@tonic-gate 
692*7c478bd9Sstevel@tonic-gate /*
693*7c478bd9Sstevel@tonic-gate  * ccp_ackci - process a received configure-ack, and return
694*7c478bd9Sstevel@tonic-gate  * 1 iff the packet was OK.
695*7c478bd9Sstevel@tonic-gate  */
696*7c478bd9Sstevel@tonic-gate static int
697*7c478bd9Sstevel@tonic-gate ccp_ackci(f, p, len)
698*7c478bd9Sstevel@tonic-gate     fsm *f;
699*7c478bd9Sstevel@tonic-gate     u_char *p;
700*7c478bd9Sstevel@tonic-gate     int len;
701*7c478bd9Sstevel@tonic-gate {
702*7c478bd9Sstevel@tonic-gate     ccp_options *go = &ccp_gotoptions[f->unit];
703*7c478bd9Sstevel@tonic-gate     u_char *p0 = p;
704*7c478bd9Sstevel@tonic-gate 
705*7c478bd9Sstevel@tonic-gate     if (go->deflate && go->deflate_correct) {
706*7c478bd9Sstevel@tonic-gate 	if (len < CILEN_DEFLATE
707*7c478bd9Sstevel@tonic-gate 	    || p[0] != CI_DEFLATE || p[1] != CILEN_DEFLATE
708*7c478bd9Sstevel@tonic-gate 	    || p[2] != DEFLATE_MAKE_OPT(go->deflate_size)
709*7c478bd9Sstevel@tonic-gate 	    || p[3] != DEFLATE_CHK_SEQUENCE)
710*7c478bd9Sstevel@tonic-gate 	    return 0;
711*7c478bd9Sstevel@tonic-gate 	/* Cope with non-standard first/fast ack */
712*7c478bd9Sstevel@tonic-gate 	if (p == p0 && len == 0)
713*7c478bd9Sstevel@tonic-gate 	    return 1;
714*7c478bd9Sstevel@tonic-gate 	p += CILEN_DEFLATE;
715*7c478bd9Sstevel@tonic-gate 	len -= CILEN_DEFLATE;
716*7c478bd9Sstevel@tonic-gate     }
717*7c478bd9Sstevel@tonic-gate     if (go->deflate && go->deflate_draft) {
718*7c478bd9Sstevel@tonic-gate 	if (len < CILEN_DEFLATE
719*7c478bd9Sstevel@tonic-gate 	    || p[0] != CI_DEFLATE_DRAFT || p[1] != CILEN_DEFLATE
720*7c478bd9Sstevel@tonic-gate 	    || p[2] != DEFLATE_MAKE_OPT(go->deflate_size)
721*7c478bd9Sstevel@tonic-gate 	    || p[3] != DEFLATE_CHK_SEQUENCE)
722*7c478bd9Sstevel@tonic-gate 	    return 0;
723*7c478bd9Sstevel@tonic-gate 	/* Cope with non-standard first/fast ack */
724*7c478bd9Sstevel@tonic-gate 	if (p == p0 && len == 0)
725*7c478bd9Sstevel@tonic-gate 	    return 1;
726*7c478bd9Sstevel@tonic-gate 	p += CILEN_DEFLATE;
727*7c478bd9Sstevel@tonic-gate 	len -= CILEN_DEFLATE;
728*7c478bd9Sstevel@tonic-gate     }
729*7c478bd9Sstevel@tonic-gate     if (go->bsd_compress) {
730*7c478bd9Sstevel@tonic-gate 	if (len < CILEN_BSD_COMPRESS
731*7c478bd9Sstevel@tonic-gate 	    || p[0] != CI_BSD_COMPRESS || p[1] != CILEN_BSD_COMPRESS
732*7c478bd9Sstevel@tonic-gate 	    || p[2] != BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits))
733*7c478bd9Sstevel@tonic-gate 	    return 0;
734*7c478bd9Sstevel@tonic-gate 	/* Cope with non-standard first/fast ack */
735*7c478bd9Sstevel@tonic-gate 	if (p == p0 && len == 0)
736*7c478bd9Sstevel@tonic-gate 	    return 1;
737*7c478bd9Sstevel@tonic-gate 	p += CILEN_BSD_COMPRESS;
738*7c478bd9Sstevel@tonic-gate 	len -= CILEN_BSD_COMPRESS;
739*7c478bd9Sstevel@tonic-gate     }
740*7c478bd9Sstevel@tonic-gate     if (go->predictor_1) {
741*7c478bd9Sstevel@tonic-gate 	if (len < CILEN_PREDICTOR_1
742*7c478bd9Sstevel@tonic-gate 	    || p[0] != CI_PREDICTOR_1 || p[1] != CILEN_PREDICTOR_1)
743*7c478bd9Sstevel@tonic-gate 	    return 0;
744*7c478bd9Sstevel@tonic-gate 	/* Cope with non-standard first/fast ack */
745*7c478bd9Sstevel@tonic-gate 	if (p == p0 && len == 0)
746*7c478bd9Sstevel@tonic-gate 	    return 1;
747*7c478bd9Sstevel@tonic-gate 	p += CILEN_PREDICTOR_1;
748*7c478bd9Sstevel@tonic-gate 	len -= CILEN_PREDICTOR_1;
749*7c478bd9Sstevel@tonic-gate     }
750*7c478bd9Sstevel@tonic-gate     if (go->predictor_2) {
751*7c478bd9Sstevel@tonic-gate 	if (len < CILEN_PREDICTOR_2
752*7c478bd9Sstevel@tonic-gate 	    || p[0] != CI_PREDICTOR_2 || p[1] != CILEN_PREDICTOR_2)
753*7c478bd9Sstevel@tonic-gate 	    return 0;
754*7c478bd9Sstevel@tonic-gate 	/* Cope with non-standard first/fast ack */
755*7c478bd9Sstevel@tonic-gate 	if (p == p0 && len == 0)
756*7c478bd9Sstevel@tonic-gate 	    return 1;
757*7c478bd9Sstevel@tonic-gate 	p += CILEN_PREDICTOR_2;
758*7c478bd9Sstevel@tonic-gate 	len -= CILEN_PREDICTOR_2;
759*7c478bd9Sstevel@tonic-gate     }
760*7c478bd9Sstevel@tonic-gate 
761*7c478bd9Sstevel@tonic-gate     /* Peer cannot ack something that wasn't sent. */
762*7c478bd9Sstevel@tonic-gate     if (len != 0)
763*7c478bd9Sstevel@tonic-gate 	return 0;
764*7c478bd9Sstevel@tonic-gate     return 1;
765*7c478bd9Sstevel@tonic-gate }
766*7c478bd9Sstevel@tonic-gate 
767*7c478bd9Sstevel@tonic-gate /*
768*7c478bd9Sstevel@tonic-gate  * ccp_nakci - process received configure-nak.
769*7c478bd9Sstevel@tonic-gate  * Returns 1 iff the nak was OK.
770*7c478bd9Sstevel@tonic-gate  */
771*7c478bd9Sstevel@tonic-gate static int
772*7c478bd9Sstevel@tonic-gate ccp_nakci(f, p, len)
773*7c478bd9Sstevel@tonic-gate     fsm *f;
774*7c478bd9Sstevel@tonic-gate     u_char *p;
775*7c478bd9Sstevel@tonic-gate     int len;
776*7c478bd9Sstevel@tonic-gate {
777*7c478bd9Sstevel@tonic-gate     ccp_options *go = &ccp_gotoptions[f->unit];
778*7c478bd9Sstevel@tonic-gate     ccp_options no;		/* options we've seen already */
779*7c478bd9Sstevel@tonic-gate     ccp_options try;		/* options to ask for next time */
780*7c478bd9Sstevel@tonic-gate 
781*7c478bd9Sstevel@tonic-gate     BZERO(&no, sizeof(no));
782*7c478bd9Sstevel@tonic-gate     try = *go;
783*7c478bd9Sstevel@tonic-gate 
784*7c478bd9Sstevel@tonic-gate     if (go->deflate && go->deflate_correct && len >= CILEN_DEFLATE &&
785*7c478bd9Sstevel@tonic-gate 	p[0] == CI_DEFLATE) {
786*7c478bd9Sstevel@tonic-gate 	no.deflate = 1;
787*7c478bd9Sstevel@tonic-gate 	/*
788*7c478bd9Sstevel@tonic-gate 	 * Peer wants us to use a different code size or something.
789*7c478bd9Sstevel@tonic-gate 	 * Stop asking for Deflate if we don't understand his suggestion.
790*7c478bd9Sstevel@tonic-gate 	 */
791*7c478bd9Sstevel@tonic-gate 	if (p[1] != CILEN_DEFLATE
792*7c478bd9Sstevel@tonic-gate 	    || DEFLATE_METHOD(p[2]) != DEFLATE_METHOD_VAL
793*7c478bd9Sstevel@tonic-gate 	    || DEFLATE_SIZE(p[2]) <= DEFLATE_MIN_SIZE
794*7c478bd9Sstevel@tonic-gate 	    || p[3] != DEFLATE_CHK_SEQUENCE)
795*7c478bd9Sstevel@tonic-gate 	    try.deflate_correct = 0;
796*7c478bd9Sstevel@tonic-gate 	else if (DEFLATE_SIZE(p[2]) < go->deflate_size)
797*7c478bd9Sstevel@tonic-gate 	    try.deflate_size = DEFLATE_SIZE(p[2]);
798*7c478bd9Sstevel@tonic-gate 	len -= p[1];
799*7c478bd9Sstevel@tonic-gate 	p += p[1];
800*7c478bd9Sstevel@tonic-gate     }
801*7c478bd9Sstevel@tonic-gate 
802*7c478bd9Sstevel@tonic-gate     if (go->deflate && go->deflate_draft && len >= CILEN_DEFLATE &&
803*7c478bd9Sstevel@tonic-gate 	p[0] == CI_DEFLATE_DRAFT) {
804*7c478bd9Sstevel@tonic-gate 	no.deflate = 1;
805*7c478bd9Sstevel@tonic-gate 	/*
806*7c478bd9Sstevel@tonic-gate 	 * Peer wants us to use a different code size or something.
807*7c478bd9Sstevel@tonic-gate 	 * Stop asking for Deflate using the old algorithm number if
808*7c478bd9Sstevel@tonic-gate 	 * we don't understand his suggestion.  (Note that this will
809*7c478bd9Sstevel@tonic-gate 	 * happen if the peer is running Magnalink instead of
810*7c478bd9Sstevel@tonic-gate 	 * old-style Deflate.)
811*7c478bd9Sstevel@tonic-gate 	 */
812*7c478bd9Sstevel@tonic-gate 	if (p[1] != CILEN_DEFLATE
813*7c478bd9Sstevel@tonic-gate 	    || DEFLATE_METHOD(p[2]) != DEFLATE_METHOD_VAL
814*7c478bd9Sstevel@tonic-gate 	    || DEFLATE_SIZE(p[2]) <= DEFLATE_MIN_SIZE
815*7c478bd9Sstevel@tonic-gate 	    || p[3] != DEFLATE_CHK_SEQUENCE)
816*7c478bd9Sstevel@tonic-gate 	    try.deflate_draft = 0;
817*7c478bd9Sstevel@tonic-gate 	else if (DEFLATE_SIZE(p[2]) < go->deflate_size)
818*7c478bd9Sstevel@tonic-gate 	    try.deflate_size = DEFLATE_SIZE(p[2]);
819*7c478bd9Sstevel@tonic-gate 	len -= p[1];
820*7c478bd9Sstevel@tonic-gate 	p += p[1];
821*7c478bd9Sstevel@tonic-gate     }
822*7c478bd9Sstevel@tonic-gate 
823*7c478bd9Sstevel@tonic-gate     if (!try.deflate_correct && !try.deflate_draft)
824*7c478bd9Sstevel@tonic-gate 	try.deflate = 0;
825*7c478bd9Sstevel@tonic-gate 
826*7c478bd9Sstevel@tonic-gate     if (go->bsd_compress && len >= CILEN_BSD_COMPRESS &&
827*7c478bd9Sstevel@tonic-gate 	p[0] == CI_BSD_COMPRESS) {
828*7c478bd9Sstevel@tonic-gate 	no.bsd_compress = 1;
829*7c478bd9Sstevel@tonic-gate 	/*
830*7c478bd9Sstevel@tonic-gate 	 * Peer wants us to use a different number of bits
831*7c478bd9Sstevel@tonic-gate 	 * or a different version.
832*7c478bd9Sstevel@tonic-gate 	 */
833*7c478bd9Sstevel@tonic-gate 	if (p[1] != CILEN_BSD_COMPRESS ||
834*7c478bd9Sstevel@tonic-gate 	    BSD_VERSION(p[2]) != BSD_CURRENT_VERSION)
835*7c478bd9Sstevel@tonic-gate 	    try.bsd_compress = 0;
836*7c478bd9Sstevel@tonic-gate 	else if (BSD_NBITS(p[2]) < go->bsd_bits)
837*7c478bd9Sstevel@tonic-gate 	    try.bsd_bits = BSD_NBITS(p[2]);
838*7c478bd9Sstevel@tonic-gate 	len -= p[1];
839*7c478bd9Sstevel@tonic-gate 	p += p[1];
840*7c478bd9Sstevel@tonic-gate     }
841*7c478bd9Sstevel@tonic-gate 
842*7c478bd9Sstevel@tonic-gate     /*
843*7c478bd9Sstevel@tonic-gate      * Predictor-1 and 2 have no options, so they can't be Naked.
844*7c478bd9Sstevel@tonic-gate      *
845*7c478bd9Sstevel@tonic-gate      * There may be remaining options but we ignore them.
846*7c478bd9Sstevel@tonic-gate      */
847*7c478bd9Sstevel@tonic-gate 
848*7c478bd9Sstevel@tonic-gate     if (f->state != OPENED)
849*7c478bd9Sstevel@tonic-gate 	*go = try;
850*7c478bd9Sstevel@tonic-gate     return 1;
851*7c478bd9Sstevel@tonic-gate }
852*7c478bd9Sstevel@tonic-gate 
853*7c478bd9Sstevel@tonic-gate /*
854*7c478bd9Sstevel@tonic-gate  * ccp_rejci - peer rejects some of our suggested compression methods.
855*7c478bd9Sstevel@tonic-gate  */
856*7c478bd9Sstevel@tonic-gate static int
857*7c478bd9Sstevel@tonic-gate ccp_rejci(f, p, len)
858*7c478bd9Sstevel@tonic-gate     fsm *f;
859*7c478bd9Sstevel@tonic-gate     u_char *p;
860*7c478bd9Sstevel@tonic-gate     int len;
861*7c478bd9Sstevel@tonic-gate {
862*7c478bd9Sstevel@tonic-gate     ccp_options *go = &ccp_gotoptions[f->unit];
863*7c478bd9Sstevel@tonic-gate     ccp_options try;		/* options to request next time */
864*7c478bd9Sstevel@tonic-gate 
865*7c478bd9Sstevel@tonic-gate     try = *go;
866*7c478bd9Sstevel@tonic-gate 
867*7c478bd9Sstevel@tonic-gate     /*
868*7c478bd9Sstevel@tonic-gate      * Cope with empty configure-rejects by ceasing to send
869*7c478bd9Sstevel@tonic-gate      * configure-requests.
870*7c478bd9Sstevel@tonic-gate      */
871*7c478bd9Sstevel@tonic-gate     if (len == 0 && all_rejected[f->unit])
872*7c478bd9Sstevel@tonic-gate 	return -1;
873*7c478bd9Sstevel@tonic-gate 
874*7c478bd9Sstevel@tonic-gate     if (go->deflate && go->deflate_correct && len >= CILEN_DEFLATE &&
875*7c478bd9Sstevel@tonic-gate 	p[0] == CI_DEFLATE && p[1] == CILEN_DEFLATE) {
876*7c478bd9Sstevel@tonic-gate 	if (p[2] != DEFLATE_MAKE_OPT(go->deflate_size)
877*7c478bd9Sstevel@tonic-gate 	    || p[3] != DEFLATE_CHK_SEQUENCE)
878*7c478bd9Sstevel@tonic-gate 	    return 0;		/* Rej is bad */
879*7c478bd9Sstevel@tonic-gate 	try.deflate_correct = 0;
880*7c478bd9Sstevel@tonic-gate 	p += CILEN_DEFLATE;
881*7c478bd9Sstevel@tonic-gate 	len -= CILEN_DEFLATE;
882*7c478bd9Sstevel@tonic-gate     }
883*7c478bd9Sstevel@tonic-gate     if (go->deflate && go->deflate_draft && len >= CILEN_DEFLATE &&
884*7c478bd9Sstevel@tonic-gate 	p[0] == CI_DEFLATE_DRAFT && p[1] == CILEN_DEFLATE) {
885*7c478bd9Sstevel@tonic-gate 	if (p[2] != DEFLATE_MAKE_OPT(go->deflate_size)
886*7c478bd9Sstevel@tonic-gate 	    || p[3] != DEFLATE_CHK_SEQUENCE)
887*7c478bd9Sstevel@tonic-gate 	    return 0;		/* Rej is bad */
888*7c478bd9Sstevel@tonic-gate 	try.deflate_draft = 0;
889*7c478bd9Sstevel@tonic-gate 	p += CILEN_DEFLATE;
890*7c478bd9Sstevel@tonic-gate 	len -= CILEN_DEFLATE;
891*7c478bd9Sstevel@tonic-gate     }
892*7c478bd9Sstevel@tonic-gate     if (!try.deflate_correct && !try.deflate_draft)
893*7c478bd9Sstevel@tonic-gate 	try.deflate = 0;
894*7c478bd9Sstevel@tonic-gate     if (go->bsd_compress && len >= CILEN_BSD_COMPRESS
895*7c478bd9Sstevel@tonic-gate 	&& p[0] == CI_BSD_COMPRESS && p[1] == CILEN_BSD_COMPRESS) {
896*7c478bd9Sstevel@tonic-gate 	if (p[2] != BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits))
897*7c478bd9Sstevel@tonic-gate 	    return 0;
898*7c478bd9Sstevel@tonic-gate 	try.bsd_compress = 0;
899*7c478bd9Sstevel@tonic-gate 	p += CILEN_BSD_COMPRESS;
900*7c478bd9Sstevel@tonic-gate 	len -= CILEN_BSD_COMPRESS;
901*7c478bd9Sstevel@tonic-gate     }
902*7c478bd9Sstevel@tonic-gate     if (go->predictor_1 && len >= CILEN_PREDICTOR_1
903*7c478bd9Sstevel@tonic-gate 	&& p[0] == CI_PREDICTOR_1 && p[1] == CILEN_PREDICTOR_1) {
904*7c478bd9Sstevel@tonic-gate 	try.predictor_1 = 0;
905*7c478bd9Sstevel@tonic-gate 	p += CILEN_PREDICTOR_1;
906*7c478bd9Sstevel@tonic-gate 	len -= CILEN_PREDICTOR_1;
907*7c478bd9Sstevel@tonic-gate     }
908*7c478bd9Sstevel@tonic-gate     if (go->predictor_2 && len >= CILEN_PREDICTOR_2
909*7c478bd9Sstevel@tonic-gate 	&& p[0] == CI_PREDICTOR_2 && p[1] == CILEN_PREDICTOR_2) {
910*7c478bd9Sstevel@tonic-gate 	try.predictor_2 = 0;
911*7c478bd9Sstevel@tonic-gate 	p += CILEN_PREDICTOR_2;
912*7c478bd9Sstevel@tonic-gate 	len -= CILEN_PREDICTOR_2;
913*7c478bd9Sstevel@tonic-gate     }
914*7c478bd9Sstevel@tonic-gate 
915*7c478bd9Sstevel@tonic-gate     if (len != 0)
916*7c478bd9Sstevel@tonic-gate 	return 0;
917*7c478bd9Sstevel@tonic-gate 
918*7c478bd9Sstevel@tonic-gate     if (f->state != OPENED)
919*7c478bd9Sstevel@tonic-gate 	*go = try;
920*7c478bd9Sstevel@tonic-gate 
921*7c478bd9Sstevel@tonic-gate     return 1;
922*7c478bd9Sstevel@tonic-gate }
923*7c478bd9Sstevel@tonic-gate 
924*7c478bd9Sstevel@tonic-gate /*
925*7c478bd9Sstevel@tonic-gate  * ccp_reqci - process a received configure-request.
926*7c478bd9Sstevel@tonic-gate  *
927*7c478bd9Sstevel@tonic-gate  * Returns CODE_CONFACK, CODE_CONFNAK or CODE_CONFREJ and the packet
928*7c478bd9Sstevel@tonic-gate  * is modified appropriately.
929*7c478bd9Sstevel@tonic-gate  */
930*7c478bd9Sstevel@tonic-gate static int
931*7c478bd9Sstevel@tonic-gate ccp_reqci(f, p, lenp, dont_nak)
932*7c478bd9Sstevel@tonic-gate     fsm *f;
933*7c478bd9Sstevel@tonic-gate     u_char *p;
934*7c478bd9Sstevel@tonic-gate     int *lenp;
935*7c478bd9Sstevel@tonic-gate     int dont_nak;
936*7c478bd9Sstevel@tonic-gate {
937*7c478bd9Sstevel@tonic-gate     int ret, newret, res;
938*7c478bd9Sstevel@tonic-gate     u_char *p0, *nakp, *rejp, *pv;
939*7c478bd9Sstevel@tonic-gate     int len, clen, type, nb;
940*7c478bd9Sstevel@tonic-gate     ccp_options *ho = &ccp_hisoptions[f->unit];
941*7c478bd9Sstevel@tonic-gate     ccp_options *ao = &ccp_allowoptions[f->unit];
942*7c478bd9Sstevel@tonic-gate 
943*7c478bd9Sstevel@tonic-gate     ret = CODE_CONFACK;
944*7c478bd9Sstevel@tonic-gate     rejp = p0 = p;
945*7c478bd9Sstevel@tonic-gate     nakp = nak_buffer;
946*7c478bd9Sstevel@tonic-gate     len = *lenp;
947*7c478bd9Sstevel@tonic-gate 
948*7c478bd9Sstevel@tonic-gate     BZERO(ho, sizeof(ccp_options));
949*7c478bd9Sstevel@tonic-gate     ho->method = (len > 0)? p[0]: -1;
950*7c478bd9Sstevel@tonic-gate 
951*7c478bd9Sstevel@tonic-gate     for (; len > 0; len -= clen, p += clen) {
952*7c478bd9Sstevel@tonic-gate 	newret = CODE_CONFACK;
953*7c478bd9Sstevel@tonic-gate 	if (len < 2 || p[1] > len) {
954*7c478bd9Sstevel@tonic-gate 	    /*
955*7c478bd9Sstevel@tonic-gate 	     * RFC 1661 page 40 -- if the option extends beyond the
956*7c478bd9Sstevel@tonic-gate 	     * packet, then discard the entire packet.
957*7c478bd9Sstevel@tonic-gate 	     */
958*7c478bd9Sstevel@tonic-gate 	    return (0);
959*7c478bd9Sstevel@tonic-gate 	}
960*7c478bd9Sstevel@tonic-gate 
961*7c478bd9Sstevel@tonic-gate 	type = p[0];
962*7c478bd9Sstevel@tonic-gate 	clen = p[1];
963*7c478bd9Sstevel@tonic-gate 
964*7c478bd9Sstevel@tonic-gate 	pv = p;
965*7c478bd9Sstevel@tonic-gate 	switch (type) {
966*7c478bd9Sstevel@tonic-gate 	case CI_DEFLATE:
967*7c478bd9Sstevel@tonic-gate 	case CI_DEFLATE_DRAFT:
968*7c478bd9Sstevel@tonic-gate 	    if (!ao->deflate ||
969*7c478bd9Sstevel@tonic-gate 		(!ao->deflate_correct && type == CI_DEFLATE) ||
970*7c478bd9Sstevel@tonic-gate 		(!ao->deflate_draft && type == CI_DEFLATE_DRAFT)) {
971*7c478bd9Sstevel@tonic-gate 		newret = CODE_CONFREJ;
972*7c478bd9Sstevel@tonic-gate 		break;
973*7c478bd9Sstevel@tonic-gate 	    }
974*7c478bd9Sstevel@tonic-gate 
975*7c478bd9Sstevel@tonic-gate 	    ho->deflate = 1;
976*7c478bd9Sstevel@tonic-gate 	    nb = clen < CILEN_DEFLATE ? ao->deflate_size : DEFLATE_SIZE(p[2]);
977*7c478bd9Sstevel@tonic-gate 	    ho->deflate_size = nb;
978*7c478bd9Sstevel@tonic-gate 	    if (clen != CILEN_DEFLATE ||
979*7c478bd9Sstevel@tonic-gate 		DEFLATE_METHOD(p[2]) != DEFLATE_METHOD_VAL ||
980*7c478bd9Sstevel@tonic-gate 		p[3] != DEFLATE_CHK_SEQUENCE || nb > ao->deflate_size ||
981*7c478bd9Sstevel@tonic-gate 		nb <= DEFLATE_MIN_SIZE) {
982*7c478bd9Sstevel@tonic-gate 		newret = CODE_CONFNAK;
983*7c478bd9Sstevel@tonic-gate 		if (dont_nak)
984*7c478bd9Sstevel@tonic-gate 		    break;
985*7c478bd9Sstevel@tonic-gate 		if (nb > ao->deflate_size)
986*7c478bd9Sstevel@tonic-gate 		    nb = ao->deflate_size;
987*7c478bd9Sstevel@tonic-gate 		else if (nb <= DEFLATE_MIN_SIZE)
988*7c478bd9Sstevel@tonic-gate 		    nb = DEFLATE_MIN_SIZE+1;
989*7c478bd9Sstevel@tonic-gate 		pv = nakp;
990*7c478bd9Sstevel@tonic-gate 		PUTCHAR(type, nakp);
991*7c478bd9Sstevel@tonic-gate 		PUTCHAR(CILEN_DEFLATE, nakp);
992*7c478bd9Sstevel@tonic-gate 		PUTCHAR(DEFLATE_MAKE_OPT(nb), nakp);
993*7c478bd9Sstevel@tonic-gate 		PUTCHAR(DEFLATE_CHK_SEQUENCE, nakp);
994*7c478bd9Sstevel@tonic-gate 	    }
995*7c478bd9Sstevel@tonic-gate 
996*7c478bd9Sstevel@tonic-gate 	    /*
997*7c478bd9Sstevel@tonic-gate 	     * Check whether we can do Deflate with the window
998*7c478bd9Sstevel@tonic-gate 	     * size they want.  If the window is too big, reduce
999*7c478bd9Sstevel@tonic-gate 	     * it until the kernel can cope and nak with that.
1000*7c478bd9Sstevel@tonic-gate 	     * We only check this for the first option.
1001*7c478bd9Sstevel@tonic-gate 	     */
1002*7c478bd9Sstevel@tonic-gate 	    if (p == p0) {
1003*7c478bd9Sstevel@tonic-gate 		for (;;) {
1004*7c478bd9Sstevel@tonic-gate 		    res = ccp_test(f->unit, pv, CILEN_DEFLATE, 1);
1005*7c478bd9Sstevel@tonic-gate 		    if (res > 0)
1006*7c478bd9Sstevel@tonic-gate 			break;		/* it's OK now */
1007*7c478bd9Sstevel@tonic-gate 		    if (res < 0 || nb <= DEFLATE_MIN_SIZE+1 || dont_nak) {
1008*7c478bd9Sstevel@tonic-gate 			newret = CODE_CONFREJ;
1009*7c478bd9Sstevel@tonic-gate 			break;
1010*7c478bd9Sstevel@tonic-gate 		    }
1011*7c478bd9Sstevel@tonic-gate 		    if (newret == CODE_CONFACK) {
1012*7c478bd9Sstevel@tonic-gate 			BCOPY(pv, nakp, CILEN_DEFLATE);
1013*7c478bd9Sstevel@tonic-gate 			pv = nakp;
1014*7c478bd9Sstevel@tonic-gate 			nakp += CILEN_DEFLATE;
1015*7c478bd9Sstevel@tonic-gate 			newret = CODE_CONFNAK;
1016*7c478bd9Sstevel@tonic-gate 		    }
1017*7c478bd9Sstevel@tonic-gate 		    --nb;
1018*7c478bd9Sstevel@tonic-gate 		    pv[2] = DEFLATE_MAKE_OPT(nb);
1019*7c478bd9Sstevel@tonic-gate 		}
1020*7c478bd9Sstevel@tonic-gate #ifdef COMP_TUNE
1021*7c478bd9Sstevel@tonic-gate 		/* Tune Deflate compression effort. */
1022*7c478bd9Sstevel@tonic-gate 		if (newret == CODE_CONFACK)
1023*7c478bd9Sstevel@tonic-gate 		    ccp_tune(f->unit, deflate_tune);
1024*7c478bd9Sstevel@tonic-gate #endif
1025*7c478bd9Sstevel@tonic-gate 	    }
1026*7c478bd9Sstevel@tonic-gate 	    break;
1027*7c478bd9Sstevel@tonic-gate 
1028*7c478bd9Sstevel@tonic-gate 	case CI_BSD_COMPRESS:
1029*7c478bd9Sstevel@tonic-gate 	    if (!ao->bsd_compress) {
1030*7c478bd9Sstevel@tonic-gate 		newret = CODE_CONFREJ;
1031*7c478bd9Sstevel@tonic-gate 		break;
1032*7c478bd9Sstevel@tonic-gate 	    }
1033*7c478bd9Sstevel@tonic-gate 
1034*7c478bd9Sstevel@tonic-gate 	    ho->bsd_compress = 1;
1035*7c478bd9Sstevel@tonic-gate 	    nb = clen < CILEN_BSD_COMPRESS ? ao->bsd_bits : BSD_NBITS(p[2]);
1036*7c478bd9Sstevel@tonic-gate 	    ho->bsd_bits = nb;
1037*7c478bd9Sstevel@tonic-gate 	    if (clen != CILEN_BSD_COMPRESS ||
1038*7c478bd9Sstevel@tonic-gate 		BSD_VERSION(p[2]) != BSD_CURRENT_VERSION ||
1039*7c478bd9Sstevel@tonic-gate 		nb > ao->bsd_bits || nb < BSD_MIN_BITS) {
1040*7c478bd9Sstevel@tonic-gate 		newret = CODE_CONFNAK;
1041*7c478bd9Sstevel@tonic-gate 		if (dont_nak)
1042*7c478bd9Sstevel@tonic-gate 		    break;
1043*7c478bd9Sstevel@tonic-gate 		if (nb > ao->bsd_bits)
1044*7c478bd9Sstevel@tonic-gate 		    nb = ao->bsd_bits;
1045*7c478bd9Sstevel@tonic-gate 		else if (nb < BSD_MIN_BITS)
1046*7c478bd9Sstevel@tonic-gate 		    nb = BSD_MIN_BITS;
1047*7c478bd9Sstevel@tonic-gate 		pv = nakp;
1048*7c478bd9Sstevel@tonic-gate 		PUTCHAR(type, nakp);
1049*7c478bd9Sstevel@tonic-gate 		PUTCHAR(CILEN_BSD_COMPRESS, nakp);
1050*7c478bd9Sstevel@tonic-gate 		PUTCHAR(BSD_MAKE_OPT(BSD_CURRENT_VERSION, nb), nakp);
1051*7c478bd9Sstevel@tonic-gate 	    }
1052*7c478bd9Sstevel@tonic-gate 
1053*7c478bd9Sstevel@tonic-gate 	    /*
1054*7c478bd9Sstevel@tonic-gate 	     * Check whether we can do BSD-Compress with the code
1055*7c478bd9Sstevel@tonic-gate 	     * size they want.  If the code size is too big, reduce
1056*7c478bd9Sstevel@tonic-gate 	     * it until the kernel can cope and nak with that.
1057*7c478bd9Sstevel@tonic-gate 	     * We only check this for the first option.
1058*7c478bd9Sstevel@tonic-gate 	     */
1059*7c478bd9Sstevel@tonic-gate 	    if (p == p0) {
1060*7c478bd9Sstevel@tonic-gate 		for (;;) {
1061*7c478bd9Sstevel@tonic-gate 		    res = ccp_test(f->unit, pv, CILEN_BSD_COMPRESS, 1);
1062*7c478bd9Sstevel@tonic-gate 		    if (res > 0)
1063*7c478bd9Sstevel@tonic-gate 			break;
1064*7c478bd9Sstevel@tonic-gate 		    if (res < 0 || nb == BSD_MIN_BITS || dont_nak) {
1065*7c478bd9Sstevel@tonic-gate 			newret = CODE_CONFREJ;
1066*7c478bd9Sstevel@tonic-gate 			break;
1067*7c478bd9Sstevel@tonic-gate 		    }
1068*7c478bd9Sstevel@tonic-gate 		    if (newret == CODE_CONFACK) {
1069*7c478bd9Sstevel@tonic-gate 			BCOPY(pv, nakp, CILEN_BSD_COMPRESS);
1070*7c478bd9Sstevel@tonic-gate 			pv = nakp;
1071*7c478bd9Sstevel@tonic-gate 			nakp += CILEN_BSD_COMPRESS;
1072*7c478bd9Sstevel@tonic-gate 			newret = CODE_CONFNAK;
1073*7c478bd9Sstevel@tonic-gate 		    }
1074*7c478bd9Sstevel@tonic-gate 		    --nb;
1075*7c478bd9Sstevel@tonic-gate 		    pv[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, nb);
1076*7c478bd9Sstevel@tonic-gate 		}
1077*7c478bd9Sstevel@tonic-gate 	    }
1078*7c478bd9Sstevel@tonic-gate 	    break;
1079*7c478bd9Sstevel@tonic-gate 
1080*7c478bd9Sstevel@tonic-gate 	case CI_PREDICTOR_1:
1081*7c478bd9Sstevel@tonic-gate 	    if (!ao->predictor_1) {
1082*7c478bd9Sstevel@tonic-gate 		newret = CODE_CONFREJ;
1083*7c478bd9Sstevel@tonic-gate 		break;
1084*7c478bd9Sstevel@tonic-gate 	    }
1085*7c478bd9Sstevel@tonic-gate 
1086*7c478bd9Sstevel@tonic-gate 	    ho->predictor_1 = 1;
1087*7c478bd9Sstevel@tonic-gate 	    if (clen != CILEN_PREDICTOR_1) {
1088*7c478bd9Sstevel@tonic-gate 		newret = CODE_CONFNAK;
1089*7c478bd9Sstevel@tonic-gate 		if (dont_nak)
1090*7c478bd9Sstevel@tonic-gate 		    break;
1091*7c478bd9Sstevel@tonic-gate 		pv = nakp;
1092*7c478bd9Sstevel@tonic-gate 		PUTCHAR(type, nakp);
1093*7c478bd9Sstevel@tonic-gate 		PUTCHAR(CILEN_PREDICTOR_1, nakp);
1094*7c478bd9Sstevel@tonic-gate 	    }
1095*7c478bd9Sstevel@tonic-gate 	    if (p == p0 &&
1096*7c478bd9Sstevel@tonic-gate 		ccp_test(f->unit, pv, CILEN_PREDICTOR_1, 1) <= 0) {
1097*7c478bd9Sstevel@tonic-gate 		newret = CODE_CONFREJ;
1098*7c478bd9Sstevel@tonic-gate 	    }
1099*7c478bd9Sstevel@tonic-gate 	    break;
1100*7c478bd9Sstevel@tonic-gate 
1101*7c478bd9Sstevel@tonic-gate 	case CI_PREDICTOR_2:
1102*7c478bd9Sstevel@tonic-gate 	    if (!ao->predictor_2) {
1103*7c478bd9Sstevel@tonic-gate 		newret = CODE_CONFREJ;
1104*7c478bd9Sstevel@tonic-gate 		break;
1105*7c478bd9Sstevel@tonic-gate 	    }
1106*7c478bd9Sstevel@tonic-gate 
1107*7c478bd9Sstevel@tonic-gate 	    ho->predictor_2 = 1;
1108*7c478bd9Sstevel@tonic-gate 	    if (clen != CILEN_PREDICTOR_2) {
1109*7c478bd9Sstevel@tonic-gate 		newret = CODE_CONFNAK;
1110*7c478bd9Sstevel@tonic-gate 		if (dont_nak)
1111*7c478bd9Sstevel@tonic-gate 		    break;
1112*7c478bd9Sstevel@tonic-gate 		pv = nakp;
1113*7c478bd9Sstevel@tonic-gate 		PUTCHAR(type, nakp);
1114*7c478bd9Sstevel@tonic-gate 		PUTCHAR(CILEN_PREDICTOR_2, nakp);
1115*7c478bd9Sstevel@tonic-gate 	    }
1116*7c478bd9Sstevel@tonic-gate 	    if (p == p0 &&
1117*7c478bd9Sstevel@tonic-gate 		ccp_test(f->unit, p, CILEN_PREDICTOR_2, 1) <= 0) {
1118*7c478bd9Sstevel@tonic-gate 		newret = CODE_CONFREJ;
1119*7c478bd9Sstevel@tonic-gate 	    }
1120*7c478bd9Sstevel@tonic-gate 	    break;
1121*7c478bd9Sstevel@tonic-gate 
1122*7c478bd9Sstevel@tonic-gate 	default:
1123*7c478bd9Sstevel@tonic-gate 	    newret = CODE_CONFREJ;
1124*7c478bd9Sstevel@tonic-gate 	    break;
1125*7c478bd9Sstevel@tonic-gate 	}
1126*7c478bd9Sstevel@tonic-gate 
1127*7c478bd9Sstevel@tonic-gate 	/* Cope with confused peers. */
1128*7c478bd9Sstevel@tonic-gate 	if (clen < 2)
1129*7c478bd9Sstevel@tonic-gate 	    clen = 2;
1130*7c478bd9Sstevel@tonic-gate 
1131*7c478bd9Sstevel@tonic-gate 	if (newret == CODE_CONFACK && ret != CODE_CONFACK)
1132*7c478bd9Sstevel@tonic-gate 	    continue;
1133*7c478bd9Sstevel@tonic-gate 	if (newret == CODE_CONFNAK) {
1134*7c478bd9Sstevel@tonic-gate 	    if (dont_nak) {
1135*7c478bd9Sstevel@tonic-gate 		newret = CODE_CONFREJ;
1136*7c478bd9Sstevel@tonic-gate 	    } else {
1137*7c478bd9Sstevel@tonic-gate 		/* Ignore subsequent nakable things if rejecting. */
1138*7c478bd9Sstevel@tonic-gate 		if (ret == CODE_CONFREJ)
1139*7c478bd9Sstevel@tonic-gate 		    continue;
1140*7c478bd9Sstevel@tonic-gate 		ret = CODE_CONFNAK;
1141*7c478bd9Sstevel@tonic-gate 	    }
1142*7c478bd9Sstevel@tonic-gate 	}
1143*7c478bd9Sstevel@tonic-gate 	if (newret == CODE_CONFREJ) {
1144*7c478bd9Sstevel@tonic-gate 	    ret = CODE_CONFREJ;
1145*7c478bd9Sstevel@tonic-gate 	    if (p != rejp)
1146*7c478bd9Sstevel@tonic-gate 		BCOPY(p, rejp, clen);
1147*7c478bd9Sstevel@tonic-gate 	    rejp += clen;
1148*7c478bd9Sstevel@tonic-gate 	}
1149*7c478bd9Sstevel@tonic-gate     }
1150*7c478bd9Sstevel@tonic-gate 
1151*7c478bd9Sstevel@tonic-gate     switch (ret) {
1152*7c478bd9Sstevel@tonic-gate     case CODE_CONFACK:
1153*7c478bd9Sstevel@tonic-gate 	*lenp = p - p0;
1154*7c478bd9Sstevel@tonic-gate 	break;
1155*7c478bd9Sstevel@tonic-gate     case CODE_CONFNAK:
1156*7c478bd9Sstevel@tonic-gate 	*lenp = nakp - nak_buffer;
1157*7c478bd9Sstevel@tonic-gate 	BCOPY(nak_buffer, p0, *lenp);
1158*7c478bd9Sstevel@tonic-gate 	break;
1159*7c478bd9Sstevel@tonic-gate     case CODE_CONFREJ:
1160*7c478bd9Sstevel@tonic-gate 	*lenp = rejp - p0;
1161*7c478bd9Sstevel@tonic-gate 	break;
1162*7c478bd9Sstevel@tonic-gate     }
1163*7c478bd9Sstevel@tonic-gate     return ret;
1164*7c478bd9Sstevel@tonic-gate }
1165*7c478bd9Sstevel@tonic-gate 
1166*7c478bd9Sstevel@tonic-gate /*
1167*7c478bd9Sstevel@tonic-gate  * Make a string name for a compression method (or 2).
1168*7c478bd9Sstevel@tonic-gate  */
1169*7c478bd9Sstevel@tonic-gate static char *
1170*7c478bd9Sstevel@tonic-gate method_name(opt, opt2)
1171*7c478bd9Sstevel@tonic-gate     ccp_options *opt, *opt2;
1172*7c478bd9Sstevel@tonic-gate {
1173*7c478bd9Sstevel@tonic-gate     static char result[64];
1174*7c478bd9Sstevel@tonic-gate 
1175*7c478bd9Sstevel@tonic-gate     if (!ANY_COMPRESS(*opt))
1176*7c478bd9Sstevel@tonic-gate 	return "(none)";
1177*7c478bd9Sstevel@tonic-gate     switch (opt->method) {
1178*7c478bd9Sstevel@tonic-gate     case CI_DEFLATE:
1179*7c478bd9Sstevel@tonic-gate     case CI_DEFLATE_DRAFT:
1180*7c478bd9Sstevel@tonic-gate 	if (opt2 != NULL && opt2->deflate_size != opt->deflate_size)
1181*7c478bd9Sstevel@tonic-gate 	    (void) slprintf(result, sizeof(result), "Deflate%s (%d/%d)",
1182*7c478bd9Sstevel@tonic-gate 		     (opt->method == CI_DEFLATE_DRAFT? "(old#)": ""),
1183*7c478bd9Sstevel@tonic-gate 		     opt->deflate_size, opt2->deflate_size);
1184*7c478bd9Sstevel@tonic-gate 	else
1185*7c478bd9Sstevel@tonic-gate 	    (void) slprintf(result, sizeof(result), "Deflate%s (%d)",
1186*7c478bd9Sstevel@tonic-gate 		     (opt->method == CI_DEFLATE_DRAFT? "(old#)": ""),
1187*7c478bd9Sstevel@tonic-gate 		     opt->deflate_size);
1188*7c478bd9Sstevel@tonic-gate 	break;
1189*7c478bd9Sstevel@tonic-gate     case CI_BSD_COMPRESS:
1190*7c478bd9Sstevel@tonic-gate 	if (opt2 != NULL && opt2->bsd_bits != opt->bsd_bits)
1191*7c478bd9Sstevel@tonic-gate 	    (void) slprintf(result, sizeof(result), "BSD-Compress (%d/%d)",
1192*7c478bd9Sstevel@tonic-gate 		     opt->bsd_bits, opt2->bsd_bits);
1193*7c478bd9Sstevel@tonic-gate 	else
1194*7c478bd9Sstevel@tonic-gate 	    (void) slprintf(result, sizeof(result), "BSD-Compress (%d)",
1195*7c478bd9Sstevel@tonic-gate 		     opt->bsd_bits);
1196*7c478bd9Sstevel@tonic-gate 	break;
1197*7c478bd9Sstevel@tonic-gate     case CI_PREDICTOR_1:
1198*7c478bd9Sstevel@tonic-gate 	return "Predictor 1";
1199*7c478bd9Sstevel@tonic-gate     case CI_PREDICTOR_2:
1200*7c478bd9Sstevel@tonic-gate 	return "Predictor 2";
1201*7c478bd9Sstevel@tonic-gate #ifdef CI_STAC
1202*7c478bd9Sstevel@tonic-gate     case CI_STAC:
1203*7c478bd9Sstevel@tonic-gate 	return "Stac";
1204*7c478bd9Sstevel@tonic-gate #endif
1205*7c478bd9Sstevel@tonic-gate #ifdef CI_MPPC
1206*7c478bd9Sstevel@tonic-gate     case CI_MPPC:
1207*7c478bd9Sstevel@tonic-gate 	return "MS-PPC";
1208*7c478bd9Sstevel@tonic-gate #endif
1209*7c478bd9Sstevel@tonic-gate     default:
1210*7c478bd9Sstevel@tonic-gate 	(void) slprintf(result, sizeof(result), "Method %d", opt->method);
1211*7c478bd9Sstevel@tonic-gate     }
1212*7c478bd9Sstevel@tonic-gate     return result;
1213*7c478bd9Sstevel@tonic-gate }
1214*7c478bd9Sstevel@tonic-gate 
1215*7c478bd9Sstevel@tonic-gate /*
1216*7c478bd9Sstevel@tonic-gate  * CCP has come up - inform the kernel driver and log a message.
1217*7c478bd9Sstevel@tonic-gate  */
1218*7c478bd9Sstevel@tonic-gate static void
1219*7c478bd9Sstevel@tonic-gate ccp_up(f)
1220*7c478bd9Sstevel@tonic-gate     fsm *f;
1221*7c478bd9Sstevel@tonic-gate {
1222*7c478bd9Sstevel@tonic-gate     ccp_options *go = &ccp_gotoptions[f->unit];
1223*7c478bd9Sstevel@tonic-gate     ccp_options *ho = &ccp_hisoptions[f->unit];
1224*7c478bd9Sstevel@tonic-gate     char method1[64];
1225*7c478bd9Sstevel@tonic-gate 
1226*7c478bd9Sstevel@tonic-gate     /*
1227*7c478bd9Sstevel@tonic-gate      * We're now open and up (running).
1228*7c478bd9Sstevel@tonic-gate      */
1229*7c478bd9Sstevel@tonic-gate     ccp_flags_set(f->unit, 1, 1);
1230*7c478bd9Sstevel@tonic-gate     if (ANY_COMPRESS(*go)) {
1231*7c478bd9Sstevel@tonic-gate 	if (ANY_COMPRESS(*ho)) {
1232*7c478bd9Sstevel@tonic-gate 	    if (go->method == ho->method) {
1233*7c478bd9Sstevel@tonic-gate 		notice("%s compression enabled", method_name(go, ho));
1234*7c478bd9Sstevel@tonic-gate 	    } else {
1235*7c478bd9Sstevel@tonic-gate 		(void) strlcpy(method1, method_name(go, NULL), sizeof(method1));
1236*7c478bd9Sstevel@tonic-gate 		notice("%s / %s compression enabled",
1237*7c478bd9Sstevel@tonic-gate 		       method1, method_name(ho, NULL));
1238*7c478bd9Sstevel@tonic-gate 	    }
1239*7c478bd9Sstevel@tonic-gate 	} else
1240*7c478bd9Sstevel@tonic-gate 	    notice("%s receive decompression enabled", method_name(go, NULL));
1241*7c478bd9Sstevel@tonic-gate     } else if (ANY_COMPRESS(*ho))
1242*7c478bd9Sstevel@tonic-gate 	notice("%s transmit compression enabled", method_name(ho, NULL));
1243*7c478bd9Sstevel@tonic-gate }
1244*7c478bd9Sstevel@tonic-gate 
1245*7c478bd9Sstevel@tonic-gate /*
1246*7c478bd9Sstevel@tonic-gate  * CCP has gone down - inform the kernel driver.
1247*7c478bd9Sstevel@tonic-gate  */
1248*7c478bd9Sstevel@tonic-gate static void
1249*7c478bd9Sstevel@tonic-gate ccp_down(f)
1250*7c478bd9Sstevel@tonic-gate     fsm *f;
1251*7c478bd9Sstevel@tonic-gate {
1252*7c478bd9Sstevel@tonic-gate     if (ccp_localstate[f->unit] & RACK_PENDING)
1253*7c478bd9Sstevel@tonic-gate 	UNTIMEOUT(ccp_rack_timeout, f);
1254*7c478bd9Sstevel@tonic-gate     /* Don't forget about peer's code rejects or ignoring of requests. */
1255*7c478bd9Sstevel@tonic-gate     ccp_localstate[f->unit] &= ~RACK_PENDING & ~RREQ_REPEAT;
1256*7c478bd9Sstevel@tonic-gate     /* We're still open, but no longer up. */
1257*7c478bd9Sstevel@tonic-gate     ccp_flags_set(f->unit, 1, 0);
1258*7c478bd9Sstevel@tonic-gate }
1259*7c478bd9Sstevel@tonic-gate 
1260*7c478bd9Sstevel@tonic-gate static int
1261*7c478bd9Sstevel@tonic-gate ccp_printpkt(p, plen, printer, arg)
1262*7c478bd9Sstevel@tonic-gate     u_char *p;
1263*7c478bd9Sstevel@tonic-gate     int plen;
1264*7c478bd9Sstevel@tonic-gate     void (*printer) __P((void *, const char *, ...));
1265*7c478bd9Sstevel@tonic-gate     void *arg;
1266*7c478bd9Sstevel@tonic-gate {
1267*7c478bd9Sstevel@tonic-gate     u_char *p0, *optend, cichar;
1268*7c478bd9Sstevel@tonic-gate     int code, id, len;
1269*7c478bd9Sstevel@tonic-gate     int optlen, clen;
1270*7c478bd9Sstevel@tonic-gate     u_short cishort;
1271*7c478bd9Sstevel@tonic-gate #ifdef CI_MPPC
1272*7c478bd9Sstevel@tonic-gate     u_int32_t cilong;
1273*7c478bd9Sstevel@tonic-gate #endif
1274*7c478bd9Sstevel@tonic-gate 
1275*7c478bd9Sstevel@tonic-gate     p0 = p;
1276*7c478bd9Sstevel@tonic-gate     if (plen < HEADERLEN) {
1277*7c478bd9Sstevel@tonic-gate 	printer(arg, "too short (%d<%d)", plen, HEADERLEN);
1278*7c478bd9Sstevel@tonic-gate 	return (0);
1279*7c478bd9Sstevel@tonic-gate     }
1280*7c478bd9Sstevel@tonic-gate     GETCHAR(code, p);
1281*7c478bd9Sstevel@tonic-gate     GETCHAR(id, p);
1282*7c478bd9Sstevel@tonic-gate     GETSHORT(len, p);
1283*7c478bd9Sstevel@tonic-gate 
1284*7c478bd9Sstevel@tonic-gate     printer(arg, " %s id=0x%x", code_name(code, 1), id);
1285*7c478bd9Sstevel@tonic-gate 
1286*7c478bd9Sstevel@tonic-gate     if (len < HEADERLEN) {
1287*7c478bd9Sstevel@tonic-gate 	printer(arg, " header length %d<%d", len, HEADERLEN);
1288*7c478bd9Sstevel@tonic-gate 	return (HEADERLEN);
1289*7c478bd9Sstevel@tonic-gate     }
1290*7c478bd9Sstevel@tonic-gate     if (len > plen) {
1291*7c478bd9Sstevel@tonic-gate 	printer(arg, " truncated (%d>%d)", len, plen);
1292*7c478bd9Sstevel@tonic-gate 	len = plen;
1293*7c478bd9Sstevel@tonic-gate     }
1294*7c478bd9Sstevel@tonic-gate     len -= HEADERLEN;
1295*7c478bd9Sstevel@tonic-gate 
1296*7c478bd9Sstevel@tonic-gate     switch (code) {
1297*7c478bd9Sstevel@tonic-gate     case CODE_CONFREQ:
1298*7c478bd9Sstevel@tonic-gate     case CODE_CONFACK:
1299*7c478bd9Sstevel@tonic-gate     case CODE_CONFNAK:
1300*7c478bd9Sstevel@tonic-gate     case CODE_CONFREJ:
1301*7c478bd9Sstevel@tonic-gate 	/* print list of possible compression methods */
1302*7c478bd9Sstevel@tonic-gate 	while (len >= 2) {
1303*7c478bd9Sstevel@tonic-gate 	    GETCHAR(code, p);
1304*7c478bd9Sstevel@tonic-gate 	    GETCHAR(clen, p);
1305*7c478bd9Sstevel@tonic-gate 	    optlen = clen;
1306*7c478bd9Sstevel@tonic-gate 	    printer(arg, " <");
1307*7c478bd9Sstevel@tonic-gate 	    if (optlen > len)
1308*7c478bd9Sstevel@tonic-gate 		optlen = len;
1309*7c478bd9Sstevel@tonic-gate 	    if (optlen < 2)
1310*7c478bd9Sstevel@tonic-gate 		optlen = 2;
1311*7c478bd9Sstevel@tonic-gate 	    len -= optlen;
1312*7c478bd9Sstevel@tonic-gate 	    optend = p + optlen - 2;
1313*7c478bd9Sstevel@tonic-gate 	    switch (code) {
1314*7c478bd9Sstevel@tonic-gate 	    case CI_DEFLATE:
1315*7c478bd9Sstevel@tonic-gate 	    case CI_DEFLATE_DRAFT:
1316*7c478bd9Sstevel@tonic-gate 		printer(arg, "deflate%s",
1317*7c478bd9Sstevel@tonic-gate 		    (code == CI_DEFLATE_DRAFT? "(old#)": ""));
1318*7c478bd9Sstevel@tonic-gate 		if (clen != CILEN_DEFLATE)
1319*7c478bd9Sstevel@tonic-gate 		    printer(arg, " length %d", clen);
1320*7c478bd9Sstevel@tonic-gate 		if (optlen >= CILEN_DEFLATE) {
1321*7c478bd9Sstevel@tonic-gate 		    GETCHAR(cichar, p);
1322*7c478bd9Sstevel@tonic-gate 		    printer(arg, " %d", DEFLATE_SIZE(cichar));
1323*7c478bd9Sstevel@tonic-gate 		    if (DEFLATE_METHOD(cichar) != DEFLATE_METHOD_VAL)
1324*7c478bd9Sstevel@tonic-gate 			printer(arg, " method %d", DEFLATE_METHOD(cichar));
1325*7c478bd9Sstevel@tonic-gate 		    GETCHAR(cichar, p);
1326*7c478bd9Sstevel@tonic-gate 		    if (cichar != DEFLATE_CHK_SEQUENCE)
1327*7c478bd9Sstevel@tonic-gate 			printer(arg, " check %d", cichar);
1328*7c478bd9Sstevel@tonic-gate 		}
1329*7c478bd9Sstevel@tonic-gate 		break;
1330*7c478bd9Sstevel@tonic-gate 	    case CI_BSD_COMPRESS:
1331*7c478bd9Sstevel@tonic-gate 		printer(arg, "bsd");
1332*7c478bd9Sstevel@tonic-gate 		if (clen != CILEN_BSD_COMPRESS)
1333*7c478bd9Sstevel@tonic-gate 		    printer(arg, " length %d", clen);
1334*7c478bd9Sstevel@tonic-gate 		if (optlen >= CILEN_BSD_COMPRESS) {
1335*7c478bd9Sstevel@tonic-gate 		    GETCHAR(cichar, p);
1336*7c478bd9Sstevel@tonic-gate 		    printer(arg, " v%d %d", BSD_VERSION(cichar),
1337*7c478bd9Sstevel@tonic-gate 			BSD_NBITS(cichar));
1338*7c478bd9Sstevel@tonic-gate 		}
1339*7c478bd9Sstevel@tonic-gate 		break;
1340*7c478bd9Sstevel@tonic-gate 	    case CI_PREDICTOR_1:
1341*7c478bd9Sstevel@tonic-gate 		printer(arg, "predictor-1");
1342*7c478bd9Sstevel@tonic-gate 		if (clen != CILEN_PREDICTOR_1)
1343*7c478bd9Sstevel@tonic-gate 		    printer(arg, " length %d", clen);
1344*7c478bd9Sstevel@tonic-gate 		break;
1345*7c478bd9Sstevel@tonic-gate 	    case CI_PREDICTOR_2:
1346*7c478bd9Sstevel@tonic-gate 		printer(arg, "predictor-2");
1347*7c478bd9Sstevel@tonic-gate 		if (clen != CILEN_PREDICTOR_2)
1348*7c478bd9Sstevel@tonic-gate 		    printer(arg, " length %d", clen);
1349*7c478bd9Sstevel@tonic-gate 		break;
1350*7c478bd9Sstevel@tonic-gate #ifdef CI_STAC
1351*7c478bd9Sstevel@tonic-gate 	    case CI_STAC:
1352*7c478bd9Sstevel@tonic-gate 		printer(arg, "Stac");
1353*7c478bd9Sstevel@tonic-gate 		if (clen != CILEN_STAC)
1354*7c478bd9Sstevel@tonic-gate 		    printer(arg, " length %d", clen);
1355*7c478bd9Sstevel@tonic-gate 		if (optlen >= CILEN_STAC) {
1356*7c478bd9Sstevel@tonic-gate 		    GETSHORT(cishort, p);
1357*7c478bd9Sstevel@tonic-gate 		    GETCHAR(cichar, p);
1358*7c478bd9Sstevel@tonic-gate 		    printer(arg, " h%d/m%d", cishort, cichar);
1359*7c478bd9Sstevel@tonic-gate 		}
1360*7c478bd9Sstevel@tonic-gate 		break;
1361*7c478bd9Sstevel@tonic-gate #endif
1362*7c478bd9Sstevel@tonic-gate #ifdef CI_MPPC
1363*7c478bd9Sstevel@tonic-gate 	    case CI_MPPC:
1364*7c478bd9Sstevel@tonic-gate 		/* There appears to be no good generic name for this one. */
1365*7c478bd9Sstevel@tonic-gate 		if (optlen >= CILEN_MPPC) {
1366*7c478bd9Sstevel@tonic-gate 		    GETLONG(cilong, p);
1367*7c478bd9Sstevel@tonic-gate 		    if (!(cilong & MPPC_COMP)) {
1368*7c478bd9Sstevel@tonic-gate 			if (cilong & MPPC_MPPE)
1369*7c478bd9Sstevel@tonic-gate 			    printer(arg, "MPPE");
1370*7c478bd9Sstevel@tonic-gate 			else
1371*7c478bd9Sstevel@tonic-gate 			    printer(arg, "MS-PPC?");
1372*7c478bd9Sstevel@tonic-gate 		    } else {
1373*7c478bd9Sstevel@tonic-gate 			if (cilong & MPPC_MPPE)
1374*7c478bd9Sstevel@tonic-gate 			    printer(arg, "MPPC+MPPE");
1375*7c478bd9Sstevel@tonic-gate 			else
1376*7c478bd9Sstevel@tonic-gate 			    printer(arg, "MPPC");
1377*7c478bd9Sstevel@tonic-gate 		    }
1378*7c478bd9Sstevel@tonic-gate 		} else {
1379*7c478bd9Sstevel@tonic-gate 		    printer(arg, "MS-?");
1380*7c478bd9Sstevel@tonic-gate 		}
1381*7c478bd9Sstevel@tonic-gate 		if (clen != CILEN_STAC)
1382*7c478bd9Sstevel@tonic-gate 		    printer(arg, " length %d", clen);
1383*7c478bd9Sstevel@tonic-gate 		break;
1384*7c478bd9Sstevel@tonic-gate #endif
1385*7c478bd9Sstevel@tonic-gate 	    default:
1386*7c478bd9Sstevel@tonic-gate 		printer(arg, "typ%d len%d ", code, clen);
1387*7c478bd9Sstevel@tonic-gate 		break;
1388*7c478bd9Sstevel@tonic-gate 	    }
1389*7c478bd9Sstevel@tonic-gate 	    if (p < optend) {
1390*7c478bd9Sstevel@tonic-gate 		if (p+8 < optend)
1391*7c478bd9Sstevel@tonic-gate 		    printer(arg, " %.8B ...", p);
1392*7c478bd9Sstevel@tonic-gate 		else
1393*7c478bd9Sstevel@tonic-gate 		    printer(arg, " %.*B", optend-p, p);
1394*7c478bd9Sstevel@tonic-gate 		p = optend;
1395*7c478bd9Sstevel@tonic-gate 	    }
1396*7c478bd9Sstevel@tonic-gate 	    printer(arg, ">");
1397*7c478bd9Sstevel@tonic-gate 	}
1398*7c478bd9Sstevel@tonic-gate 	break;
1399*7c478bd9Sstevel@tonic-gate 
1400*7c478bd9Sstevel@tonic-gate     case CODE_TERMACK:
1401*7c478bd9Sstevel@tonic-gate     case CODE_TERMREQ:
1402*7c478bd9Sstevel@tonic-gate 	if (len > 0) {
1403*7c478bd9Sstevel@tonic-gate 	    if (len == 2) {
1404*7c478bd9Sstevel@tonic-gate 		GETSHORT(cishort, p);
1405*7c478bd9Sstevel@tonic-gate 		printer(arg, " history %d", cishort);
1406*7c478bd9Sstevel@tonic-gate 		len = 0;
1407*7c478bd9Sstevel@tonic-gate 	    } else if (*p >= ' ' && *p < 0x7f) {
1408*7c478bd9Sstevel@tonic-gate 		printer(arg, " ");
1409*7c478bd9Sstevel@tonic-gate 		print_string((char *)p, len, printer, arg);
1410*7c478bd9Sstevel@tonic-gate 		p += len;
1411*7c478bd9Sstevel@tonic-gate 		len = 0;
1412*7c478bd9Sstevel@tonic-gate 	    }
1413*7c478bd9Sstevel@tonic-gate 	}
1414*7c478bd9Sstevel@tonic-gate 	break;
1415*7c478bd9Sstevel@tonic-gate     }
1416*7c478bd9Sstevel@tonic-gate 
1417*7c478bd9Sstevel@tonic-gate     /* dump out the rest of the packet in hex */
1418*7c478bd9Sstevel@tonic-gate     if (len > 0) {
1419*7c478bd9Sstevel@tonic-gate 	if (len > 8)
1420*7c478bd9Sstevel@tonic-gate 	    printer(arg, " %.8B ...", p);
1421*7c478bd9Sstevel@tonic-gate 	else
1422*7c478bd9Sstevel@tonic-gate 	    printer(arg, " %.*B", len, p);
1423*7c478bd9Sstevel@tonic-gate 	p += len;
1424*7c478bd9Sstevel@tonic-gate     }
1425*7c478bd9Sstevel@tonic-gate 
1426*7c478bd9Sstevel@tonic-gate     return p - p0;
1427*7c478bd9Sstevel@tonic-gate }
1428*7c478bd9Sstevel@tonic-gate 
1429*7c478bd9Sstevel@tonic-gate /*
1430*7c478bd9Sstevel@tonic-gate  * We have received a packet that the decompressor failed to
1431*7c478bd9Sstevel@tonic-gate  * decompress.  Here we would expect to issue a reset-request, but
1432*7c478bd9Sstevel@tonic-gate  * Motorola has a patent on resetting the compressor as a result of
1433*7c478bd9Sstevel@tonic-gate  * detecting an error in the decompressed data after decompression.
1434*7c478bd9Sstevel@tonic-gate  * (See US patent 5,130,993; international patent publication number
1435*7c478bd9Sstevel@tonic-gate  * WO 91/10289; Australian patent 73296/91.)
1436*7c478bd9Sstevel@tonic-gate  *
1437*7c478bd9Sstevel@tonic-gate  * So we ask the kernel whether the error was detected after
1438*7c478bd9Sstevel@tonic-gate  * decompression; if it was, we take CCP down, thus disabling
1439*7c478bd9Sstevel@tonic-gate  * compression :-(, otherwise we issue the reset-request.
1440*7c478bd9Sstevel@tonic-gate  */
1441*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1442*7c478bd9Sstevel@tonic-gate static void
1443*7c478bd9Sstevel@tonic-gate ccp_datainput(unit, pkt, len)
1444*7c478bd9Sstevel@tonic-gate     int unit;
1445*7c478bd9Sstevel@tonic-gate     u_char *pkt;
1446*7c478bd9Sstevel@tonic-gate     int len;
1447*7c478bd9Sstevel@tonic-gate {
1448*7c478bd9Sstevel@tonic-gate     fsm *f;
1449*7c478bd9Sstevel@tonic-gate 
1450*7c478bd9Sstevel@tonic-gate     f = &ccp_fsm[unit];
1451*7c478bd9Sstevel@tonic-gate     if (f->state == OPENED) {
1452*7c478bd9Sstevel@tonic-gate 	if (ccp_fatal_error(unit)) {
1453*7c478bd9Sstevel@tonic-gate 	    /*
1454*7c478bd9Sstevel@tonic-gate 	     * Disable compression by taking CCP down.
1455*7c478bd9Sstevel@tonic-gate 	     */
1456*7c478bd9Sstevel@tonic-gate 	    error("Lost compression sync: disabling compression");
1457*7c478bd9Sstevel@tonic-gate 	    ccp_close(unit, "Lost compression sync");
1458*7c478bd9Sstevel@tonic-gate 	} else {
1459*7c478bd9Sstevel@tonic-gate 	    /*
1460*7c478bd9Sstevel@tonic-gate 	     * Send a reset-request to reset the peer's compressor, if
1461*7c478bd9Sstevel@tonic-gate 	     * possible.  We don't do anything if we are still waiting
1462*7c478bd9Sstevel@tonic-gate 	     * for an acknowledgement to a previous reset-request (to
1463*7c478bd9Sstevel@tonic-gate 	     * avoid flooding the peer).  We reopen CCP if the peer
1464*7c478bd9Sstevel@tonic-gate 	     * doesn't like hearing about CCP Reset-Request (Cisco
1465*7c478bd9Sstevel@tonic-gate 	     * sends CCP Code-Reject for Reset-Request).  (Reopen
1466*7c478bd9Sstevel@tonic-gate 	     * automatically clears the flags and cancels the
1467*7c478bd9Sstevel@tonic-gate 	     * timeout.)
1468*7c478bd9Sstevel@tonic-gate 	     */
1469*7c478bd9Sstevel@tonic-gate 	    if (ccp_localstate[f->unit] & RREQ_REJECTED) {
1470*7c478bd9Sstevel@tonic-gate 		dbglog("reopening CCP to reset peer's compressor");
1471*7c478bd9Sstevel@tonic-gate 		ccp_open(f->unit);
1472*7c478bd9Sstevel@tonic-gate 	    } else if (ccp_localstate[f->unit] & RACK_PENDING) {
1473*7c478bd9Sstevel@tonic-gate 		/* Send another reset request; we're out of sequence. */
1474*7c478bd9Sstevel@tonic-gate 		ccp_localstate[f->unit] |= RREQ_REPEAT;
1475*7c478bd9Sstevel@tonic-gate 	    } else {
1476*7c478bd9Sstevel@tonic-gate 		dbglog("sending CCP Reset-Request to reset peer's compressor");
1477*7c478bd9Sstevel@tonic-gate 		fsm_sdata(f, CCP_RESETREQ, f->reqid = ++f->id, NULL, 0);
1478*7c478bd9Sstevel@tonic-gate 		TIMEOUT(ccp_rack_timeout, f, RACKTIMEOUT);
1479*7c478bd9Sstevel@tonic-gate 		ccp_localstate[f->unit] |= RACK_PENDING;
1480*7c478bd9Sstevel@tonic-gate 	    }
1481*7c478bd9Sstevel@tonic-gate 	}
1482*7c478bd9Sstevel@tonic-gate     }
1483*7c478bd9Sstevel@tonic-gate }
1484*7c478bd9Sstevel@tonic-gate 
1485*7c478bd9Sstevel@tonic-gate /*
1486*7c478bd9Sstevel@tonic-gate  * Timeout waiting for reset-ack.
1487*7c478bd9Sstevel@tonic-gate  */
1488*7c478bd9Sstevel@tonic-gate static void
1489*7c478bd9Sstevel@tonic-gate ccp_rack_timeout(arg)
1490*7c478bd9Sstevel@tonic-gate     void *arg;
1491*7c478bd9Sstevel@tonic-gate {
1492*7c478bd9Sstevel@tonic-gate     fsm *f = arg;
1493*7c478bd9Sstevel@tonic-gate 
1494*7c478bd9Sstevel@tonic-gate     /* Timeout; no longer pending. */
1495*7c478bd9Sstevel@tonic-gate     ccp_localstate[f->unit] &= ~RACK_PENDING;
1496*7c478bd9Sstevel@tonic-gate 
1497*7c478bd9Sstevel@tonic-gate     /* Frankly, it's a coding flaw if this occurs. */
1498*7c478bd9Sstevel@tonic-gate     if (f->state != OPENED)
1499*7c478bd9Sstevel@tonic-gate 	return;
1500*7c478bd9Sstevel@tonic-gate 
1501*7c478bd9Sstevel@tonic-gate     if (ccp_localstate[f->unit] & RREQ_IGNORED) {
1502*7c478bd9Sstevel@tonic-gate 	info("peer ignored our CCP Reset-Request twice; reopen instead");
1503*7c478bd9Sstevel@tonic-gate 	ccp_localstate[f->unit] =
1504*7c478bd9Sstevel@tonic-gate 	    (ccp_localstate[f->unit] & ~RREQ_IGNORED) | RREQ_REJECTED;
1505*7c478bd9Sstevel@tonic-gate 	ccp_open(f->unit);
1506*7c478bd9Sstevel@tonic-gate     } else if (ccp_localstate[f->unit] & RREQ_REPEAT) {
1507*7c478bd9Sstevel@tonic-gate 	dbglog("sending another CCP Reset-Request on timeout");
1508*7c478bd9Sstevel@tonic-gate 	fsm_sdata(f, CCP_RESETREQ, f->reqid, NULL, 0);
1509*7c478bd9Sstevel@tonic-gate 	TIMEOUT(ccp_rack_timeout, f, RACKTIMEOUT);
1510*7c478bd9Sstevel@tonic-gate 	ccp_localstate[f->unit] =
1511*7c478bd9Sstevel@tonic-gate 	    (ccp_localstate[f->unit] & ~RREQ_REPEAT) | RREQ_IGNORED |
1512*7c478bd9Sstevel@tonic-gate 	    RACK_PENDING;
1513*7c478bd9Sstevel@tonic-gate     } else {
1514*7c478bd9Sstevel@tonic-gate 	dbglog("timeout waiting for CCP Reset-Ack; hope for the best");
1515*7c478bd9Sstevel@tonic-gate 	ccp_localstate[f->unit] |= RREQ_IGNORED;
1516*7c478bd9Sstevel@tonic-gate     }
1517*7c478bd9Sstevel@tonic-gate }
1518