1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * spppcomp.c - STREAMS module for kernel-level compression and CCP support.
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
5*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
6*7c478bd9Sstevel@tonic-gate  *
7*7c478bd9Sstevel@tonic-gate  * Permission to use, copy, modify, and distribute this software and its
8*7c478bd9Sstevel@tonic-gate  * documentation is hereby granted, provided that the above copyright
9*7c478bd9Sstevel@tonic-gate  * notice appears in all copies.
10*7c478bd9Sstevel@tonic-gate  *
11*7c478bd9Sstevel@tonic-gate  * SUN MAKES NO REPRESENTATION OR WARRANTIES ABOUT THE SUITABILITY OF
12*7c478bd9Sstevel@tonic-gate  * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
13*7c478bd9Sstevel@tonic-gate  * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
14*7c478bd9Sstevel@tonic-gate  * PARTICULAR PURPOSE, OR NON-INFRINGEMENT.  SUN SHALL NOT BE LIABLE FOR
15*7c478bd9Sstevel@tonic-gate  * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
16*7c478bd9Sstevel@tonic-gate  * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES
17*7c478bd9Sstevel@tonic-gate  *
18*7c478bd9Sstevel@tonic-gate  * Copyright (c) 1994 The Australian National University.
19*7c478bd9Sstevel@tonic-gate  * All rights reserved.
20*7c478bd9Sstevel@tonic-gate  *
21*7c478bd9Sstevel@tonic-gate  * Permission to use, copy, modify, and distribute this software and its
22*7c478bd9Sstevel@tonic-gate  * documentation is hereby granted, provided that the above copyright
23*7c478bd9Sstevel@tonic-gate  * notice appears in all copies.  This software is provided without any
24*7c478bd9Sstevel@tonic-gate  * warranty, express or implied. The Australian National University
25*7c478bd9Sstevel@tonic-gate  * makes no representations about the suitability of this software for
26*7c478bd9Sstevel@tonic-gate  * any purpose.
27*7c478bd9Sstevel@tonic-gate  *
28*7c478bd9Sstevel@tonic-gate  * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
29*7c478bd9Sstevel@tonic-gate  * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
30*7c478bd9Sstevel@tonic-gate  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
31*7c478bd9Sstevel@tonic-gate  * THE AUSTRALIAN NATIONAL UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY
32*7c478bd9Sstevel@tonic-gate  * OF SUCH DAMAGE.
33*7c478bd9Sstevel@tonic-gate  *
34*7c478bd9Sstevel@tonic-gate  * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
35*7c478bd9Sstevel@tonic-gate  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
36*7c478bd9Sstevel@tonic-gate  * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
37*7c478bd9Sstevel@tonic-gate  * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
38*7c478bd9Sstevel@tonic-gate  * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
39*7c478bd9Sstevel@tonic-gate  * OR MODIFICATIONS.
40*7c478bd9Sstevel@tonic-gate  *
41*7c478bd9Sstevel@tonic-gate  * This module is derived from the original SVR4 STREAMS PPP compression
42*7c478bd9Sstevel@tonic-gate  * module originally written by Paul Mackerras <paul.mackerras@cs.anu.edu.au>.
43*7c478bd9Sstevel@tonic-gate  *
44*7c478bd9Sstevel@tonic-gate  * James Carlson <james.d.carlson@sun.com> and Adi Masputra
45*7c478bd9Sstevel@tonic-gate  * <adi.masputra@sun.com> rewrote and restructured the code for improved
46*7c478bd9Sstevel@tonic-gate  * performance and scalability.
47*7c478bd9Sstevel@tonic-gate  */
48*7c478bd9Sstevel@tonic-gate 
49*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
50*7c478bd9Sstevel@tonic-gate #define	RCSID	"$Id: spppcomp.c,v 1.0 2000/05/08 01:10:12 masputra Exp $"
51*7c478bd9Sstevel@tonic-gate 
52*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
53*7c478bd9Sstevel@tonic-gate #include <sys/debug.h>
54*7c478bd9Sstevel@tonic-gate #include <sys/param.h>
55*7c478bd9Sstevel@tonic-gate #include <sys/stream.h>
56*7c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
57*7c478bd9Sstevel@tonic-gate #include <sys/errno.h>
58*7c478bd9Sstevel@tonic-gate #include <sys/conf.h>
59*7c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h>
60*7c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
61*7c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
62*7c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
63*7c478bd9Sstevel@tonic-gate #include <sys/kstat.h>
64*7c478bd9Sstevel@tonic-gate #include <sys/strsun.h>
65*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
66*7c478bd9Sstevel@tonic-gate #include <netinet/in.h>
67*7c478bd9Sstevel@tonic-gate #include <netinet/ip.h>
68*7c478bd9Sstevel@tonic-gate #include <net/ppp_defs.h>
69*7c478bd9Sstevel@tonic-gate #include <net/pppio.h>
70*7c478bd9Sstevel@tonic-gate #include <net/vjcompress.h>
71*7c478bd9Sstevel@tonic-gate 
72*7c478bd9Sstevel@tonic-gate /* Defined for platform-neutral include file */
73*7c478bd9Sstevel@tonic-gate #define	PACKETPTR	mblk_t *
74*7c478bd9Sstevel@tonic-gate #include <net/ppp-comp.h>
75*7c478bd9Sstevel@tonic-gate 
76*7c478bd9Sstevel@tonic-gate #include "s_common.h"
77*7c478bd9Sstevel@tonic-gate 
78*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
79*7c478bd9Sstevel@tonic-gate #define	SPC_DEBUG
80*7c478bd9Sstevel@tonic-gate #endif
81*7c478bd9Sstevel@tonic-gate #include "spppcomp.h"
82*7c478bd9Sstevel@tonic-gate 
83*7c478bd9Sstevel@tonic-gate /*
84*7c478bd9Sstevel@tonic-gate  * This is used to tag official Solaris sources.  Please do not define
85*7c478bd9Sstevel@tonic-gate  * "INTERNAL_BUILD" when building this software outside of Sun
86*7c478bd9Sstevel@tonic-gate  * Microsystems.
87*7c478bd9Sstevel@tonic-gate  */
88*7c478bd9Sstevel@tonic-gate #ifdef INTERNAL_BUILD
89*7c478bd9Sstevel@tonic-gate /* MODINFO is limited to 32 characters. */
90*7c478bd9Sstevel@tonic-gate const char spppcomp_module_description[] = "PPP 4.0 compression v%I%";
91*7c478bd9Sstevel@tonic-gate #else /* INTERNAL_BUILD */
92*7c478bd9Sstevel@tonic-gate const char spppcomp_module_description[] =
93*7c478bd9Sstevel@tonic-gate 	"ANU PPP compression $Revision: 1.16$ ";
94*7c478bd9Sstevel@tonic-gate 
95*7c478bd9Sstevel@tonic-gate /* LINTED */
96*7c478bd9Sstevel@tonic-gate static const char buildtime[] = "Built " __DATE__ " at " __TIME__
97*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
98*7c478bd9Sstevel@tonic-gate " DEBUG"
99*7c478bd9Sstevel@tonic-gate #endif
100*7c478bd9Sstevel@tonic-gate "\n";
101*7c478bd9Sstevel@tonic-gate #endif /* INTERNAL_BUILD */
102*7c478bd9Sstevel@tonic-gate 
103*7c478bd9Sstevel@tonic-gate static int	spppcomp_open(queue_t *, dev_t *, int, int, cred_t *);
104*7c478bd9Sstevel@tonic-gate static int	spppcomp_close(queue_t *, int, cred_t *);
105*7c478bd9Sstevel@tonic-gate static int	spppcomp_rput(queue_t *, mblk_t *);
106*7c478bd9Sstevel@tonic-gate static int	spppcomp_rsrv(queue_t *);
107*7c478bd9Sstevel@tonic-gate static int	spppcomp_wput(queue_t *, mblk_t *);
108*7c478bd9Sstevel@tonic-gate static int	spppcomp_wsrv(queue_t *);
109*7c478bd9Sstevel@tonic-gate 
110*7c478bd9Sstevel@tonic-gate #define	PPPCOMP_MI_MINPSZ	(0)
111*7c478bd9Sstevel@tonic-gate #define	PPPCOMP_MI_MAXPSZ	(INFPSZ)
112*7c478bd9Sstevel@tonic-gate #define	PPPCOMP_MI_HIWAT	(PPP_MTU * 20)
113*7c478bd9Sstevel@tonic-gate #define	PPPCOMP_MI_LOWAT	(PPP_MTU * 18)
114*7c478bd9Sstevel@tonic-gate 
115*7c478bd9Sstevel@tonic-gate static struct module_info spppcomp_modinfo = {
116*7c478bd9Sstevel@tonic-gate 	COMP_MOD_ID,		/* mi_idnum */
117*7c478bd9Sstevel@tonic-gate 	COMP_MOD_NAME,		/* mi_idname */
118*7c478bd9Sstevel@tonic-gate 	PPPCOMP_MI_MINPSZ,	/* mi_minpsz */
119*7c478bd9Sstevel@tonic-gate 	PPPCOMP_MI_MAXPSZ,	/* mi_maxpsz */
120*7c478bd9Sstevel@tonic-gate 	PPPCOMP_MI_HIWAT,	/* mi_hiwat */
121*7c478bd9Sstevel@tonic-gate 	PPPCOMP_MI_LOWAT	/* mi_lowat */
122*7c478bd9Sstevel@tonic-gate };
123*7c478bd9Sstevel@tonic-gate 
124*7c478bd9Sstevel@tonic-gate static struct qinit spppcomp_rinit = {
125*7c478bd9Sstevel@tonic-gate 	spppcomp_rput,		/* qi_putp */
126*7c478bd9Sstevel@tonic-gate 	spppcomp_rsrv,		/* qi_srvp */
127*7c478bd9Sstevel@tonic-gate 	spppcomp_open,		/* qi_qopen */
128*7c478bd9Sstevel@tonic-gate 	spppcomp_close,		/* qi_qclose */
129*7c478bd9Sstevel@tonic-gate 	NULL,			/* qi_qadmin */
130*7c478bd9Sstevel@tonic-gate 	&spppcomp_modinfo,	/* qi_minfo */
131*7c478bd9Sstevel@tonic-gate 	NULL			/* qi_mstat */
132*7c478bd9Sstevel@tonic-gate };
133*7c478bd9Sstevel@tonic-gate 
134*7c478bd9Sstevel@tonic-gate static struct qinit spppcomp_winit = {
135*7c478bd9Sstevel@tonic-gate 	spppcomp_wput,		/* qi_putp */
136*7c478bd9Sstevel@tonic-gate 	spppcomp_wsrv,		/* qi_srvp */
137*7c478bd9Sstevel@tonic-gate 	NULL,			/* qi_qopen */
138*7c478bd9Sstevel@tonic-gate 	NULL,			/* qi_qclose */
139*7c478bd9Sstevel@tonic-gate 	NULL,			/* qi_qadmin */
140*7c478bd9Sstevel@tonic-gate 	&spppcomp_modinfo,	/* qi_minfo */
141*7c478bd9Sstevel@tonic-gate 	NULL			/* qi_mstat */
142*7c478bd9Sstevel@tonic-gate };
143*7c478bd9Sstevel@tonic-gate 
144*7c478bd9Sstevel@tonic-gate struct streamtab spppcomp_tab = {
145*7c478bd9Sstevel@tonic-gate 	&spppcomp_rinit,	/* st_rdinit */
146*7c478bd9Sstevel@tonic-gate 	&spppcomp_winit,	/* st_wrinit */
147*7c478bd9Sstevel@tonic-gate 	NULL,			/* st_muxrinit */
148*7c478bd9Sstevel@tonic-gate 	NULL			/* st_muxwinit */
149*7c478bd9Sstevel@tonic-gate };
150*7c478bd9Sstevel@tonic-gate 
151*7c478bd9Sstevel@tonic-gate /* Set non-zero to debug algorithm-specific problems alone. */
152*7c478bd9Sstevel@tonic-gate #define	ALG_DEBUG	0
153*7c478bd9Sstevel@tonic-gate 
154*7c478bd9Sstevel@tonic-gate #define	MAX_IPHLEN	(0x0f << 2)
155*7c478bd9Sstevel@tonic-gate #define	MAX_TCPHLEN	(0x0f << 2)
156*7c478bd9Sstevel@tonic-gate #define	MAX_TCPIPHLEN	(MAX_IPHLEN + MAX_TCPHLEN) /* max TCP/IP header size */
157*7c478bd9Sstevel@tonic-gate #define	MAX_VJHDR	(20)		/* max VJ compressed header size (?) */
158*7c478bd9Sstevel@tonic-gate 
159*7c478bd9Sstevel@tonic-gate #if 0
160*7c478bd9Sstevel@tonic-gate #define	DBGSTART	CE_CONT, COMP_MOD_NAME "%d: "
161*7c478bd9Sstevel@tonic-gate #define	CKDEBUG(x)	cmn_err x
162*7c478bd9Sstevel@tonic-gate #else
163*7c478bd9Sstevel@tonic-gate #define	DBGSTART	COMP_MOD_NAME "%d: "
164*7c478bd9Sstevel@tonic-gate #define	CKDEBUG(x)	printf x
165*7c478bd9Sstevel@tonic-gate #endif
166*7c478bd9Sstevel@tonic-gate #define	CPDEBUG(x)	(IS_CP_KDEBUG(cp) ? CKDEBUG(x) : (void)0)
167*7c478bd9Sstevel@tonic-gate 
168*7c478bd9Sstevel@tonic-gate /*
169*7c478bd9Sstevel@tonic-gate  * List of compressors we know about.
170*7c478bd9Sstevel@tonic-gate  */
171*7c478bd9Sstevel@tonic-gate #if DO_BSD_COMPRESS
172*7c478bd9Sstevel@tonic-gate extern struct compressor ppp_bsd_compress;
173*7c478bd9Sstevel@tonic-gate #endif
174*7c478bd9Sstevel@tonic-gate #if DO_DEFLATE
175*7c478bd9Sstevel@tonic-gate extern struct compressor ppp_deflate;
176*7c478bd9Sstevel@tonic-gate extern struct compressor ppp_deflate_draft;
177*7c478bd9Sstevel@tonic-gate #endif
178*7c478bd9Sstevel@tonic-gate 
179*7c478bd9Sstevel@tonic-gate struct compressor *ppp_compressors[] = {
180*7c478bd9Sstevel@tonic-gate #if DO_BSD_COMPRESS
181*7c478bd9Sstevel@tonic-gate 	&ppp_bsd_compress,
182*7c478bd9Sstevel@tonic-gate #endif
183*7c478bd9Sstevel@tonic-gate #if DO_DEFLATE
184*7c478bd9Sstevel@tonic-gate 	&ppp_deflate,
185*7c478bd9Sstevel@tonic-gate 	&ppp_deflate_draft,
186*7c478bd9Sstevel@tonic-gate #endif
187*7c478bd9Sstevel@tonic-gate 	NULL
188*7c478bd9Sstevel@tonic-gate };
189*7c478bd9Sstevel@tonic-gate 
190*7c478bd9Sstevel@tonic-gate /*
191*7c478bd9Sstevel@tonic-gate  * LCP_USE_DFLT() removed by James Carlson.  RFC 1661 section 6.6 has
192*7c478bd9Sstevel@tonic-gate  * this to say on the topic:
193*7c478bd9Sstevel@tonic-gate  *
194*7c478bd9Sstevel@tonic-gate  *    The Address and Control fields MUST NOT be compressed when sending
195*7c478bd9Sstevel@tonic-gate  *    any LCP packet.  This rule guarantees unambiguous recognition of
196*7c478bd9Sstevel@tonic-gate  *    LCP packets.
197*7c478bd9Sstevel@tonic-gate  */
198*7c478bd9Sstevel@tonic-gate 
199*7c478bd9Sstevel@tonic-gate static void	spppcomp_ioctl(queue_t *, mblk_t *, sppp_comp_t *);
200*7c478bd9Sstevel@tonic-gate static int	spppcomp_mctl(queue_t *, mblk_t *);
201*7c478bd9Sstevel@tonic-gate static mblk_t	*spppcomp_outpkt(queue_t *, mblk_t *);
202*7c478bd9Sstevel@tonic-gate static mblk_t	*spppcomp_inpkt(queue_t *, mblk_t *);
203*7c478bd9Sstevel@tonic-gate static int	spppcomp_kstat_update(kstat_t *, int);
204*7c478bd9Sstevel@tonic-gate static void	comp_ccp(queue_t *, mblk_t *, sppp_comp_t *, boolean_t);
205*7c478bd9Sstevel@tonic-gate 
206*7c478bd9Sstevel@tonic-gate /*
207*7c478bd9Sstevel@tonic-gate  * Values for checking inter-arrival times on interrupt stacks.  These
208*7c478bd9Sstevel@tonic-gate  * are used to prevent CPU hogging in interrupt context.
209*7c478bd9Sstevel@tonic-gate  */
210*7c478bd9Sstevel@tonic-gate #define	MIN_ARRIVAL_TIME	5000000	/* interarrival time in nanoseconds */
211*7c478bd9Sstevel@tonic-gate #define	MAX_FAST_ARRIVALS	10	/* maximum packet count */
212*7c478bd9Sstevel@tonic-gate hrtime_t spppcomp_min_arrival = MIN_ARRIVAL_TIME;
213*7c478bd9Sstevel@tonic-gate 
214*7c478bd9Sstevel@tonic-gate static const char *kstats_names[] = {
215*7c478bd9Sstevel@tonic-gate #ifdef SPCDEBUG_KSTATS_NAMES
216*7c478bd9Sstevel@tonic-gate 	SPPPCOMP_KSTATS_NAMES,
217*7c478bd9Sstevel@tonic-gate 	SPCDEBUG_KSTATS_NAMES
218*7c478bd9Sstevel@tonic-gate #else
219*7c478bd9Sstevel@tonic-gate 	SPPPCOMP_KSTATS_NAMES
220*7c478bd9Sstevel@tonic-gate #endif
221*7c478bd9Sstevel@tonic-gate };
222*7c478bd9Sstevel@tonic-gate static const char *kstats64_names[] = { SPPPCOMP_KSTATS64_NAMES };
223*7c478bd9Sstevel@tonic-gate 
224*7c478bd9Sstevel@tonic-gate /*
225*7c478bd9Sstevel@tonic-gate  * spppcomp_open()
226*7c478bd9Sstevel@tonic-gate  *
227*7c478bd9Sstevel@tonic-gate  * MT-Perimeters:
228*7c478bd9Sstevel@tonic-gate  *    exclusive inner.
229*7c478bd9Sstevel@tonic-gate  *
230*7c478bd9Sstevel@tonic-gate  * Description:
231*7c478bd9Sstevel@tonic-gate  *    Common open procedure for module.
232*7c478bd9Sstevel@tonic-gate  */
233*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
234*7c478bd9Sstevel@tonic-gate static int
235*7c478bd9Sstevel@tonic-gate spppcomp_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp)
236*7c478bd9Sstevel@tonic-gate {
237*7c478bd9Sstevel@tonic-gate 	sppp_comp_t	*cp;
238*7c478bd9Sstevel@tonic-gate 
239*7c478bd9Sstevel@tonic-gate 	ASSERT(q != NULL);
240*7c478bd9Sstevel@tonic-gate 	ASSERT(devp != NULL);
241*7c478bd9Sstevel@tonic-gate 
242*7c478bd9Sstevel@tonic-gate 	if (q->q_ptr != NULL) {
243*7c478bd9Sstevel@tonic-gate 		return (0);
244*7c478bd9Sstevel@tonic-gate 	}
245*7c478bd9Sstevel@tonic-gate 	if (sflag != MODOPEN) {
246*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
247*7c478bd9Sstevel@tonic-gate 	}
248*7c478bd9Sstevel@tonic-gate 	cp = (sppp_comp_t *)kmem_zalloc(sizeof (sppp_comp_t), KM_SLEEP);
249*7c478bd9Sstevel@tonic-gate 	ASSERT(cp != NULL);
250*7c478bd9Sstevel@tonic-gate 	q->q_ptr = WR(q)->q_ptr = (caddr_t)cp;
251*7c478bd9Sstevel@tonic-gate 
252*7c478bd9Sstevel@tonic-gate 	cp->cp_mru = PPP_MRU;
253*7c478bd9Sstevel@tonic-gate 	cp->cp_mtu = PPP_MTU;
254*7c478bd9Sstevel@tonic-gate 
255*7c478bd9Sstevel@tonic-gate 	mutex_init(&cp->cp_pair_lock, NULL, MUTEX_DRIVER, NULL);
256*7c478bd9Sstevel@tonic-gate 	vj_compress_init(&cp->cp_vj, -1);
257*7c478bd9Sstevel@tonic-gate 	cp->cp_nxslots = -1;
258*7c478bd9Sstevel@tonic-gate 	cp->cp_effort = -1;
259*7c478bd9Sstevel@tonic-gate 
260*7c478bd9Sstevel@tonic-gate 	qprocson(q);
261*7c478bd9Sstevel@tonic-gate 	return (0);
262*7c478bd9Sstevel@tonic-gate }
263*7c478bd9Sstevel@tonic-gate 
264*7c478bd9Sstevel@tonic-gate /*
265*7c478bd9Sstevel@tonic-gate  * spppcomp_close()
266*7c478bd9Sstevel@tonic-gate  *
267*7c478bd9Sstevel@tonic-gate  * MT-Perimeters:
268*7c478bd9Sstevel@tonic-gate  *    exclusive inner.
269*7c478bd9Sstevel@tonic-gate  *
270*7c478bd9Sstevel@tonic-gate  * Description:
271*7c478bd9Sstevel@tonic-gate  *    Common close procedure for module.
272*7c478bd9Sstevel@tonic-gate  */
273*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
274*7c478bd9Sstevel@tonic-gate static int
275*7c478bd9Sstevel@tonic-gate spppcomp_close(queue_t *q, int flag, cred_t *credp)
276*7c478bd9Sstevel@tonic-gate {
277*7c478bd9Sstevel@tonic-gate 	sppp_comp_t	*cp;
278*7c478bd9Sstevel@tonic-gate 
279*7c478bd9Sstevel@tonic-gate 	ASSERT(q != NULL);
280*7c478bd9Sstevel@tonic-gate 	ASSERT(q->q_ptr != NULL);
281*7c478bd9Sstevel@tonic-gate 	cp = (sppp_comp_t *)q->q_ptr;
282*7c478bd9Sstevel@tonic-gate 
283*7c478bd9Sstevel@tonic-gate 	qprocsoff(q);
284*7c478bd9Sstevel@tonic-gate 
285*7c478bd9Sstevel@tonic-gate 	CPDEBUG((DBGSTART "close flags=0x%b\n",
286*7c478bd9Sstevel@tonic-gate 	    (IS_CP_HASUNIT(cp) ? cp->cp_unit : -1), cp->cp_flags,
287*7c478bd9Sstevel@tonic-gate 	    CP_FLAGSSTR));
288*7c478bd9Sstevel@tonic-gate 	mutex_destroy(&cp->cp_pair_lock);
289*7c478bd9Sstevel@tonic-gate 	if (cp->cp_kstats) {
290*7c478bd9Sstevel@tonic-gate 		ASSERT(IS_CP_HASUNIT(cp));
291*7c478bd9Sstevel@tonic-gate 		kstat_delete(cp->cp_kstats);
292*7c478bd9Sstevel@tonic-gate 	}
293*7c478bd9Sstevel@tonic-gate 	if (cp->cp_xstate != NULL) {
294*7c478bd9Sstevel@tonic-gate 		(*cp->cp_xcomp->comp_free)(cp->cp_xstate);
295*7c478bd9Sstevel@tonic-gate 	}
296*7c478bd9Sstevel@tonic-gate 	if (cp->cp_rstate != NULL) {
297*7c478bd9Sstevel@tonic-gate 		(*cp->cp_rcomp->decomp_free)(cp->cp_rstate);
298*7c478bd9Sstevel@tonic-gate 	}
299*7c478bd9Sstevel@tonic-gate 	kmem_free(cp, sizeof (sppp_comp_t));
300*7c478bd9Sstevel@tonic-gate 	q->q_ptr = WR(q)->q_ptr = NULL;
301*7c478bd9Sstevel@tonic-gate 
302*7c478bd9Sstevel@tonic-gate 	return (0);
303*7c478bd9Sstevel@tonic-gate }
304*7c478bd9Sstevel@tonic-gate 
305*7c478bd9Sstevel@tonic-gate /*
306*7c478bd9Sstevel@tonic-gate  * spppcomp_wput()
307*7c478bd9Sstevel@tonic-gate  *
308*7c478bd9Sstevel@tonic-gate  * MT-Perimeters:
309*7c478bd9Sstevel@tonic-gate  *    exclusive inner.
310*7c478bd9Sstevel@tonic-gate  *
311*7c478bd9Sstevel@tonic-gate  * Description:
312*7c478bd9Sstevel@tonic-gate  *    Write-side put procedure.  Packets from above us arrive here.
313*7c478bd9Sstevel@tonic-gate  *
314*7c478bd9Sstevel@tonic-gate  *	The data handling logic is a little tricky here.  We defer to
315*7c478bd9Sstevel@tonic-gate  *	the service routine if q_first isn't NULL (to preserve message
316*7c478bd9Sstevel@tonic-gate  *	ordering after deferring a previous message), bcanputnext() is
317*7c478bd9Sstevel@tonic-gate  *	FALSE (to handle flow control), or we need a lot of processing
318*7c478bd9Sstevel@tonic-gate  *	and we're in an interrupt context (on the theory that we're
319*7c478bd9Sstevel@tonic-gate  *	already on a very long call stack at that point).  Since many
320*7c478bd9Sstevel@tonic-gate  *	callers will be in a non-interrupt context, this means that
321*7c478bd9Sstevel@tonic-gate  *	most processing will be performed here in-line, and deferral
322*7c478bd9Sstevel@tonic-gate  *	occurs only when necessary.
323*7c478bd9Sstevel@tonic-gate  */
324*7c478bd9Sstevel@tonic-gate static int
325*7c478bd9Sstevel@tonic-gate spppcomp_wput(queue_t *q, mblk_t *mp)
326*7c478bd9Sstevel@tonic-gate {
327*7c478bd9Sstevel@tonic-gate 	sppp_comp_t	*cp;
328*7c478bd9Sstevel@tonic-gate 	int flag;
329*7c478bd9Sstevel@tonic-gate 
330*7c478bd9Sstevel@tonic-gate 	ASSERT(q != NULL);
331*7c478bd9Sstevel@tonic-gate 	ASSERT(q->q_ptr != NULL);
332*7c478bd9Sstevel@tonic-gate 	cp = (sppp_comp_t *)q->q_ptr;
333*7c478bd9Sstevel@tonic-gate 	ASSERT(mp != NULL && mp->b_rptr != NULL);
334*7c478bd9Sstevel@tonic-gate 
335*7c478bd9Sstevel@tonic-gate 	switch (MTYPE(mp)) {
336*7c478bd9Sstevel@tonic-gate 	case M_DATA:
337*7c478bd9Sstevel@tonic-gate 		if (q->q_first != NULL || !bcanputnext(q, mp->b_band) ||
338*7c478bd9Sstevel@tonic-gate 		    ((cp->cp_flags & (COMP_VJC|CCP_COMP_RUN)) &&
339*7c478bd9Sstevel@tonic-gate 			servicing_interrupt())) {
340*7c478bd9Sstevel@tonic-gate #ifdef SPC_DEBUG
341*7c478bd9Sstevel@tonic-gate 			cp->cp_out_queued++;
342*7c478bd9Sstevel@tonic-gate #endif
343*7c478bd9Sstevel@tonic-gate 			(void) putq(q, mp);
344*7c478bd9Sstevel@tonic-gate 		} else {
345*7c478bd9Sstevel@tonic-gate #ifdef SPC_DEBUG
346*7c478bd9Sstevel@tonic-gate 			cp->cp_out_handled++;
347*7c478bd9Sstevel@tonic-gate #endif
348*7c478bd9Sstevel@tonic-gate 			if ((mp = spppcomp_outpkt(q, mp)) != NULL) {
349*7c478bd9Sstevel@tonic-gate 				putnext(q, mp);
350*7c478bd9Sstevel@tonic-gate 			}
351*7c478bd9Sstevel@tonic-gate 		}
352*7c478bd9Sstevel@tonic-gate 		break;
353*7c478bd9Sstevel@tonic-gate 	case M_IOCTL:
354*7c478bd9Sstevel@tonic-gate 		spppcomp_ioctl(q, mp, cp);
355*7c478bd9Sstevel@tonic-gate 		break;
356*7c478bd9Sstevel@tonic-gate 	case M_CTL:
357*7c478bd9Sstevel@tonic-gate 		mutex_enter(&cp->cp_pair_lock);
358*7c478bd9Sstevel@tonic-gate 		flag = spppcomp_mctl(q, mp);
359*7c478bd9Sstevel@tonic-gate 		mutex_exit(&cp->cp_pair_lock);
360*7c478bd9Sstevel@tonic-gate 		if (flag != 0)
361*7c478bd9Sstevel@tonic-gate 			putnext(q, mp);
362*7c478bd9Sstevel@tonic-gate 		else
363*7c478bd9Sstevel@tonic-gate 			freemsg(mp);
364*7c478bd9Sstevel@tonic-gate 		break;
365*7c478bd9Sstevel@tonic-gate 	case M_FLUSH:
366*7c478bd9Sstevel@tonic-gate 		CPDEBUG((DBGSTART "wput M_FLUSH (0x%x) flags=0x%b\n",
367*7c478bd9Sstevel@tonic-gate 		    (IS_CP_HASUNIT(cp) ? cp->cp_unit : -1),
368*7c478bd9Sstevel@tonic-gate 		    *mp->b_rptr, cp->cp_flags,	CP_FLAGSSTR));
369*7c478bd9Sstevel@tonic-gate 		/*
370*7c478bd9Sstevel@tonic-gate 		 * Just discard pending data.  For CCP, any compressor
371*7c478bd9Sstevel@tonic-gate 		 * dictionary sequencing problems caused by this will
372*7c478bd9Sstevel@tonic-gate 		 * have to be handled by the compression protocol in
373*7c478bd9Sstevel@tonic-gate 		 * use.  For VJ, we need to tell the compressor to
374*7c478bd9Sstevel@tonic-gate 		 * start over.
375*7c478bd9Sstevel@tonic-gate 		 */
376*7c478bd9Sstevel@tonic-gate 		if (*mp->b_rptr & FLUSHW) {
377*7c478bd9Sstevel@tonic-gate 			mutex_enter(&cp->cp_pair_lock);
378*7c478bd9Sstevel@tonic-gate 			flushq(q, FLUSHDATA);
379*7c478bd9Sstevel@tonic-gate 			vj_compress_init(&cp->cp_vj, cp->cp_nxslots);
380*7c478bd9Sstevel@tonic-gate 			mutex_exit(&cp->cp_pair_lock);
381*7c478bd9Sstevel@tonic-gate 		}
382*7c478bd9Sstevel@tonic-gate 		putnext(q, mp);
383*7c478bd9Sstevel@tonic-gate 		break;
384*7c478bd9Sstevel@tonic-gate 	default:
385*7c478bd9Sstevel@tonic-gate 		putnext(q, mp);
386*7c478bd9Sstevel@tonic-gate 		break;
387*7c478bd9Sstevel@tonic-gate 	}
388*7c478bd9Sstevel@tonic-gate 	return (0);
389*7c478bd9Sstevel@tonic-gate }
390*7c478bd9Sstevel@tonic-gate 
391*7c478bd9Sstevel@tonic-gate /*
392*7c478bd9Sstevel@tonic-gate  * spppcomp_wsrv()
393*7c478bd9Sstevel@tonic-gate  *
394*7c478bd9Sstevel@tonic-gate  * MT-Perimeters:
395*7c478bd9Sstevel@tonic-gate  *    exclusive inner
396*7c478bd9Sstevel@tonic-gate  *
397*7c478bd9Sstevel@tonic-gate  * Description:
398*7c478bd9Sstevel@tonic-gate  *    Write-side service procedure.
399*7c478bd9Sstevel@tonic-gate  */
400*7c478bd9Sstevel@tonic-gate static int
401*7c478bd9Sstevel@tonic-gate spppcomp_wsrv(queue_t *q)
402*7c478bd9Sstevel@tonic-gate {
403*7c478bd9Sstevel@tonic-gate 	mblk_t		*mp;
404*7c478bd9Sstevel@tonic-gate 
405*7c478bd9Sstevel@tonic-gate 	ASSERT(q != NULL);
406*7c478bd9Sstevel@tonic-gate 	ASSERT(q->q_ptr != NULL);
407*7c478bd9Sstevel@tonic-gate 
408*7c478bd9Sstevel@tonic-gate 	while ((mp = getq(q)) != NULL) {
409*7c478bd9Sstevel@tonic-gate 		/* We should only place M_DATA on the service queue. */
410*7c478bd9Sstevel@tonic-gate 		ASSERT(MTYPE(mp) == M_DATA);
411*7c478bd9Sstevel@tonic-gate 		/*
412*7c478bd9Sstevel@tonic-gate 		 * If the module below us is flow-controlled, then put
413*7c478bd9Sstevel@tonic-gate 		 * this message back on the queue again.
414*7c478bd9Sstevel@tonic-gate 		 */
415*7c478bd9Sstevel@tonic-gate 		if (!bcanputnext(q, mp->b_band)) {
416*7c478bd9Sstevel@tonic-gate 			(void) putbq(q, mp);
417*7c478bd9Sstevel@tonic-gate 			break;
418*7c478bd9Sstevel@tonic-gate 		}
419*7c478bd9Sstevel@tonic-gate 		if ((mp = spppcomp_outpkt(q, mp)) != NULL) {
420*7c478bd9Sstevel@tonic-gate 			putnext(q, mp);
421*7c478bd9Sstevel@tonic-gate 		}
422*7c478bd9Sstevel@tonic-gate 	}
423*7c478bd9Sstevel@tonic-gate 	return (0);
424*7c478bd9Sstevel@tonic-gate }
425*7c478bd9Sstevel@tonic-gate 
426*7c478bd9Sstevel@tonic-gate /*
427*7c478bd9Sstevel@tonic-gate  * spppcomp_outpkt()
428*7c478bd9Sstevel@tonic-gate  *
429*7c478bd9Sstevel@tonic-gate  * MT-Perimeters:
430*7c478bd9Sstevel@tonic-gate  *    exclusive inner
431*7c478bd9Sstevel@tonic-gate  *
432*7c478bd9Sstevel@tonic-gate  * Description:
433*7c478bd9Sstevel@tonic-gate  *    Process outgoing packet.  Returns new mblk_t pointer on success
434*7c478bd9Sstevel@tonic-gate  *    (caller should do putnext through q), NULL on failure (packet has
435*7c478bd9Sstevel@tonic-gate  *    been discarded).
436*7c478bd9Sstevel@tonic-gate  */
437*7c478bd9Sstevel@tonic-gate static mblk_t *
438*7c478bd9Sstevel@tonic-gate spppcomp_outpkt(queue_t *q, mblk_t *mp)
439*7c478bd9Sstevel@tonic-gate {
440*7c478bd9Sstevel@tonic-gate 	mblk_t		*zmp;
441*7c478bd9Sstevel@tonic-gate 	int		len;
442*7c478bd9Sstevel@tonic-gate 	ushort_t	proto;
443*7c478bd9Sstevel@tonic-gate 	sppp_comp_t	*cp;
444*7c478bd9Sstevel@tonic-gate 
445*7c478bd9Sstevel@tonic-gate 	ASSERT(q != NULL);
446*7c478bd9Sstevel@tonic-gate 	ASSERT(mp != NULL);
447*7c478bd9Sstevel@tonic-gate 	cp = (sppp_comp_t *)q->q_ptr;
448*7c478bd9Sstevel@tonic-gate 	ASSERT(cp != NULL);
449*7c478bd9Sstevel@tonic-gate 
450*7c478bd9Sstevel@tonic-gate 	/*
451*7c478bd9Sstevel@tonic-gate 	 * If the entire data size of the mblk is less than the length of the
452*7c478bd9Sstevel@tonic-gate 	 * PPP header, then free it. We can't do much with such message anyway,
453*7c478bd9Sstevel@tonic-gate 	 * since we can't determine what the PPP protocol is.
454*7c478bd9Sstevel@tonic-gate 	 */
455*7c478bd9Sstevel@tonic-gate 	len = msgsize(mp);
456*7c478bd9Sstevel@tonic-gate 	if (MBLKL(mp) < PPP_HDRLEN) {
457*7c478bd9Sstevel@tonic-gate #ifdef SPC_DEBUG
458*7c478bd9Sstevel@tonic-gate 		mutex_enter(&cp->cp_pair_lock);
459*7c478bd9Sstevel@tonic-gate 		cp->cp_omsg_pull++;
460*7c478bd9Sstevel@tonic-gate 		mutex_exit(&cp->cp_pair_lock);
461*7c478bd9Sstevel@tonic-gate #endif
462*7c478bd9Sstevel@tonic-gate 		zmp = msgpullup(mp, PPP_HDRLEN);
463*7c478bd9Sstevel@tonic-gate 		freemsg(mp);
464*7c478bd9Sstevel@tonic-gate 		if ((mp = zmp) == NULL)
465*7c478bd9Sstevel@tonic-gate 			goto msg_oerror;
466*7c478bd9Sstevel@tonic-gate 	}
467*7c478bd9Sstevel@tonic-gate 
468*7c478bd9Sstevel@tonic-gate 	proto = PPP_PROTOCOL(mp->b_rptr);
469*7c478bd9Sstevel@tonic-gate 
470*7c478bd9Sstevel@tonic-gate 	/*
471*7c478bd9Sstevel@tonic-gate 	 * Do VJ compression if requested.
472*7c478bd9Sstevel@tonic-gate 	 */
473*7c478bd9Sstevel@tonic-gate 	if (proto == PPP_IP && IS_COMP_VJC(cp) &&
474*7c478bd9Sstevel@tonic-gate 	    MSG_BYTE(mp, PPP_HDRLEN+offsetof(struct ip, ip_p)) ==
475*7c478bd9Sstevel@tonic-gate 	    IPPROTO_TCP) {
476*7c478bd9Sstevel@tonic-gate 		uchar_t		*vjhdr;
477*7c478bd9Sstevel@tonic-gate 		int		type;
478*7c478bd9Sstevel@tonic-gate 		uint32_t	indata[(PPP_HDRLEN+MAX_TCPIPHLEN) /
479*7c478bd9Sstevel@tonic-gate 		    sizeof (uint32_t)];
480*7c478bd9Sstevel@tonic-gate 		uchar_t		*dp;
481*7c478bd9Sstevel@tonic-gate 		int		tocopy, copied;
482*7c478bd9Sstevel@tonic-gate 		mblk_t		*fmb;
483*7c478bd9Sstevel@tonic-gate 		void		*srcp;
484*7c478bd9Sstevel@tonic-gate 		int		thislen;
485*7c478bd9Sstevel@tonic-gate 
486*7c478bd9Sstevel@tonic-gate 
487*7c478bd9Sstevel@tonic-gate 		tocopy = copied = MIN(len, sizeof (indata));
488*7c478bd9Sstevel@tonic-gate 		/*
489*7c478bd9Sstevel@tonic-gate 		 * If we can alter this dblk, and there's enough data
490*7c478bd9Sstevel@tonic-gate 		 * here to work with, and it's nicely aligned, then
491*7c478bd9Sstevel@tonic-gate 		 * avoid the data copy.
492*7c478bd9Sstevel@tonic-gate 		 */
493*7c478bd9Sstevel@tonic-gate 		if (DB_REF(mp) == 1 && MBLKL(mp) >= tocopy &&
494*7c478bd9Sstevel@tonic-gate 		    ((uintptr_t)mp->b_rptr & 3) == 0) {
495*7c478bd9Sstevel@tonic-gate 			/* Save off the address/control */
496*7c478bd9Sstevel@tonic-gate 			indata[0] = *(uint32_t *)mp->b_rptr;
497*7c478bd9Sstevel@tonic-gate 			srcp = (void *)(mp->b_rptr + PPP_HDRLEN);
498*7c478bd9Sstevel@tonic-gate 		} else {
499*7c478bd9Sstevel@tonic-gate 			fmb = mp;
500*7c478bd9Sstevel@tonic-gate 			dp = (uchar_t *)indata;
501*7c478bd9Sstevel@tonic-gate 			while (tocopy > 0) {
502*7c478bd9Sstevel@tonic-gate 				thislen = MBLKL(fmb);
503*7c478bd9Sstevel@tonic-gate 				if (tocopy > thislen) {
504*7c478bd9Sstevel@tonic-gate 					bcopy(fmb->b_rptr, dp, thislen);
505*7c478bd9Sstevel@tonic-gate 					dp += thislen;
506*7c478bd9Sstevel@tonic-gate 					tocopy -= thislen;
507*7c478bd9Sstevel@tonic-gate 					fmb = fmb->b_cont;
508*7c478bd9Sstevel@tonic-gate 				} else {
509*7c478bd9Sstevel@tonic-gate 					bcopy(fmb->b_rptr, dp, tocopy);
510*7c478bd9Sstevel@tonic-gate 					break;
511*7c478bd9Sstevel@tonic-gate 				}
512*7c478bd9Sstevel@tonic-gate 			}
513*7c478bd9Sstevel@tonic-gate 			srcp = (void *)(indata + PPP_HDRLEN/sizeof (*indata));
514*7c478bd9Sstevel@tonic-gate 		}
515*7c478bd9Sstevel@tonic-gate 
516*7c478bd9Sstevel@tonic-gate 		type = vj_compress_tcp((struct ip *)srcp, len - PPP_HDRLEN,
517*7c478bd9Sstevel@tonic-gate 		    &cp->cp_vj, IS_COMP_VJCCID(cp), &vjhdr);
518*7c478bd9Sstevel@tonic-gate 
519*7c478bd9Sstevel@tonic-gate 		/*
520*7c478bd9Sstevel@tonic-gate 		 * If we're going to modify this packet, then we can't modify
521*7c478bd9Sstevel@tonic-gate 		 * someone else's data.  Copy instead.
522*7c478bd9Sstevel@tonic-gate 		 *
523*7c478bd9Sstevel@tonic-gate 		 * (It would be nice to be able to avoid this data copy if CCP
524*7c478bd9Sstevel@tonic-gate 		 * is also enabled.  That would require extensive
525*7c478bd9Sstevel@tonic-gate 		 * modifications to the compression code.  Users should be
526*7c478bd9Sstevel@tonic-gate 		 * told to disable VJ compression when using CCP.)
527*7c478bd9Sstevel@tonic-gate 		 */
528*7c478bd9Sstevel@tonic-gate 		if (type != TYPE_IP && DB_REF(mp) > 1) {
529*7c478bd9Sstevel@tonic-gate #ifdef SPC_DEBUG
530*7c478bd9Sstevel@tonic-gate 			mutex_enter(&cp->cp_pair_lock);
531*7c478bd9Sstevel@tonic-gate 			cp->cp_omsg_dcopy++;
532*7c478bd9Sstevel@tonic-gate 			mutex_exit(&cp->cp_pair_lock);
533*7c478bd9Sstevel@tonic-gate #endif
534*7c478bd9Sstevel@tonic-gate 			/* Copy just altered portion. */
535*7c478bd9Sstevel@tonic-gate 			zmp = msgpullup(mp, copied);
536*7c478bd9Sstevel@tonic-gate 			freemsg(mp);
537*7c478bd9Sstevel@tonic-gate 			if ((mp = zmp) == NULL)
538*7c478bd9Sstevel@tonic-gate 				goto msg_oerror;
539*7c478bd9Sstevel@tonic-gate 		}
540*7c478bd9Sstevel@tonic-gate 
541*7c478bd9Sstevel@tonic-gate 		switch (type) {
542*7c478bd9Sstevel@tonic-gate 		case TYPE_UNCOMPRESSED_TCP:
543*7c478bd9Sstevel@tonic-gate 			mp->b_rptr[3] = proto = PPP_VJC_UNCOMP;
544*7c478bd9Sstevel@tonic-gate 			/* No need to update if it was done in place. */
545*7c478bd9Sstevel@tonic-gate 			if (srcp ==
546*7c478bd9Sstevel@tonic-gate 			    (void *)(indata + PPP_HDRLEN / sizeof (*indata))) {
547*7c478bd9Sstevel@tonic-gate 				thislen = PPP_HDRLEN +
548*7c478bd9Sstevel@tonic-gate 				    offsetof(struct ip, ip_p);
549*7c478bd9Sstevel@tonic-gate 				zmp = mp;
550*7c478bd9Sstevel@tonic-gate 				while (zmp != NULL) {
551*7c478bd9Sstevel@tonic-gate 					if (MBLKL(zmp) > thislen) {
552*7c478bd9Sstevel@tonic-gate 						zmp->b_rptr[thislen] =
553*7c478bd9Sstevel@tonic-gate 						    ((struct ip *)srcp)->ip_p;
554*7c478bd9Sstevel@tonic-gate 						break;
555*7c478bd9Sstevel@tonic-gate 					}
556*7c478bd9Sstevel@tonic-gate 					thislen -= MBLKL(zmp);
557*7c478bd9Sstevel@tonic-gate 					zmp = zmp->b_cont;
558*7c478bd9Sstevel@tonic-gate 				}
559*7c478bd9Sstevel@tonic-gate 			}
560*7c478bd9Sstevel@tonic-gate 			break;
561*7c478bd9Sstevel@tonic-gate 
562*7c478bd9Sstevel@tonic-gate 		case TYPE_COMPRESSED_TCP:
563*7c478bd9Sstevel@tonic-gate 			/* Calculate amount to remove from front */
564*7c478bd9Sstevel@tonic-gate 			thislen = vjhdr - (uchar_t *)srcp;
565*7c478bd9Sstevel@tonic-gate 			ASSERT(thislen >= 0);
566*7c478bd9Sstevel@tonic-gate 
567*7c478bd9Sstevel@tonic-gate 			/* Try to do a cheap adjmsg by arithmetic first. */
568*7c478bd9Sstevel@tonic-gate 			dp = mp->b_rptr + thislen;
569*7c478bd9Sstevel@tonic-gate 			if (dp > mp->b_wptr) {
570*7c478bd9Sstevel@tonic-gate 				if (!adjmsg(mp, thislen)) {
571*7c478bd9Sstevel@tonic-gate 					freemsg(mp);
572*7c478bd9Sstevel@tonic-gate 					goto msg_oerror;
573*7c478bd9Sstevel@tonic-gate 				}
574*7c478bd9Sstevel@tonic-gate 				dp = mp->b_rptr;
575*7c478bd9Sstevel@tonic-gate 			}
576*7c478bd9Sstevel@tonic-gate 
577*7c478bd9Sstevel@tonic-gate 			/*
578*7c478bd9Sstevel@tonic-gate 			 * Now make sure first block is big enough to
579*7c478bd9Sstevel@tonic-gate 			 * receive modified data.  If we modified in
580*7c478bd9Sstevel@tonic-gate 			 * place, then no need to check or copy.
581*7c478bd9Sstevel@tonic-gate 			 */
582*7c478bd9Sstevel@tonic-gate 			copied -= thislen;
583*7c478bd9Sstevel@tonic-gate 			ASSERT(copied >= PPP_HDRLEN);
584*7c478bd9Sstevel@tonic-gate 			if (srcp !=
585*7c478bd9Sstevel@tonic-gate 			    (void *)(indata + PPP_HDRLEN / sizeof (*indata)))
586*7c478bd9Sstevel@tonic-gate 				copied = 0;
587*7c478bd9Sstevel@tonic-gate 			mp->b_rptr = dp;
588*7c478bd9Sstevel@tonic-gate 			if (MBLKL(mp) < copied) {
589*7c478bd9Sstevel@tonic-gate 				zmp = msgpullup(mp, copied);
590*7c478bd9Sstevel@tonic-gate 				freemsg(mp);
591*7c478bd9Sstevel@tonic-gate 				if ((mp = zmp) == NULL)
592*7c478bd9Sstevel@tonic-gate 					goto msg_oerror;
593*7c478bd9Sstevel@tonic-gate 				dp = mp->b_rptr;
594*7c478bd9Sstevel@tonic-gate 			}
595*7c478bd9Sstevel@tonic-gate 
596*7c478bd9Sstevel@tonic-gate 			*dp++ = ((uchar_t *)indata)[0];	/* address */
597*7c478bd9Sstevel@tonic-gate 			*dp++ = ((uchar_t *)indata)[1];	/* control  */
598*7c478bd9Sstevel@tonic-gate 			*dp++ = 0;			/* protocol */
599*7c478bd9Sstevel@tonic-gate 			*dp++ = proto = PPP_VJC_COMP;	/* protocol */
600*7c478bd9Sstevel@tonic-gate 			copied -= PPP_HDRLEN;
601*7c478bd9Sstevel@tonic-gate 			if (copied > 0) {
602*7c478bd9Sstevel@tonic-gate 				bcopy(vjhdr, dp, copied);
603*7c478bd9Sstevel@tonic-gate 			}
604*7c478bd9Sstevel@tonic-gate 			break;
605*7c478bd9Sstevel@tonic-gate 		}
606*7c478bd9Sstevel@tonic-gate 	}
607*7c478bd9Sstevel@tonic-gate 
608*7c478bd9Sstevel@tonic-gate 	/*
609*7c478bd9Sstevel@tonic-gate 	 * Do packet compression if enabled.
610*7c478bd9Sstevel@tonic-gate 	 */
611*7c478bd9Sstevel@tonic-gate 	if (proto == PPP_CCP) {
612*7c478bd9Sstevel@tonic-gate 		/*
613*7c478bd9Sstevel@tonic-gate 		 * Handle any negotiation packets by changing compressor
614*7c478bd9Sstevel@tonic-gate 		 * state.  Doing this here rather than with an ioctl keeps
615*7c478bd9Sstevel@tonic-gate 		 * the negotiation and the data flow in sync.
616*7c478bd9Sstevel@tonic-gate 		 */
617*7c478bd9Sstevel@tonic-gate 		mutex_enter(&cp->cp_pair_lock);
618*7c478bd9Sstevel@tonic-gate 		comp_ccp(q, mp, cp, B_FALSE);
619*7c478bd9Sstevel@tonic-gate 		mutex_exit(&cp->cp_pair_lock);
620*7c478bd9Sstevel@tonic-gate 	} else if (proto != PPP_LCP && IS_CCP_COMP_RUN(cp) &&
621*7c478bd9Sstevel@tonic-gate 	    cp->cp_xstate != NULL) {
622*7c478bd9Sstevel@tonic-gate 		mblk_t	*cmp = NULL;
623*7c478bd9Sstevel@tonic-gate 
624*7c478bd9Sstevel@tonic-gate 		len = msgsize(mp);
625*7c478bd9Sstevel@tonic-gate 		len = (*cp->cp_xcomp->compress)(cp->cp_xstate, &cmp, mp, len,
626*7c478bd9Sstevel@tonic-gate 			(IS_CCP_ISUP(cp) ? cp->cp_mtu + PPP_HDRLEN : 0));
627*7c478bd9Sstevel@tonic-gate 
628*7c478bd9Sstevel@tonic-gate 		if (cmp != NULL) {
629*7c478bd9Sstevel@tonic-gate 			/* Success!  Discard uncompressed version */
630*7c478bd9Sstevel@tonic-gate 			cmp->b_band = mp->b_band;
631*7c478bd9Sstevel@tonic-gate 			freemsg(mp);
632*7c478bd9Sstevel@tonic-gate 			mp = cmp;
633*7c478bd9Sstevel@tonic-gate 		}
634*7c478bd9Sstevel@tonic-gate 		if (len < 0) {
635*7c478bd9Sstevel@tonic-gate 			/*
636*7c478bd9Sstevel@tonic-gate 			 * Compressor failure; must discard this
637*7c478bd9Sstevel@tonic-gate 			 * packet because the compressor dictionary is
638*7c478bd9Sstevel@tonic-gate 			 * now corrupt.
639*7c478bd9Sstevel@tonic-gate 			 */
640*7c478bd9Sstevel@tonic-gate 			freemsg(mp);
641*7c478bd9Sstevel@tonic-gate 			mutex_enter(&cp->cp_pair_lock);
642*7c478bd9Sstevel@tonic-gate 			cp->cp_stats.ppp_oerrors++;
643*7c478bd9Sstevel@tonic-gate 			mutex_exit(&cp->cp_pair_lock);
644*7c478bd9Sstevel@tonic-gate 			(void) putnextctl1(RD(q), M_CTL, PPPCTL_OERROR);
645*7c478bd9Sstevel@tonic-gate 			return (NULL);
646*7c478bd9Sstevel@tonic-gate 		}
647*7c478bd9Sstevel@tonic-gate 	}
648*7c478bd9Sstevel@tonic-gate 
649*7c478bd9Sstevel@tonic-gate 	/*
650*7c478bd9Sstevel@tonic-gate 	 * If either address and control field compression or protocol field
651*7c478bd9Sstevel@tonic-gate 	 * compression is enabled, then we'll need a writable packet.  Copy if
652*7c478bd9Sstevel@tonic-gate 	 * necessary.
653*7c478bd9Sstevel@tonic-gate 	 */
654*7c478bd9Sstevel@tonic-gate 	if ((cp->cp_flags & (COMP_AC|COMP_PROT)) && DB_REF(mp) > 1) {
655*7c478bd9Sstevel@tonic-gate #ifdef SPC_DEBUG
656*7c478bd9Sstevel@tonic-gate 		mutex_enter(&cp->cp_pair_lock);
657*7c478bd9Sstevel@tonic-gate 		cp->cp_omsg_dcopy++;
658*7c478bd9Sstevel@tonic-gate 		mutex_exit(&cp->cp_pair_lock);
659*7c478bd9Sstevel@tonic-gate #endif
660*7c478bd9Sstevel@tonic-gate 		zmp = copymsg(mp);
661*7c478bd9Sstevel@tonic-gate 		freemsg(mp);
662*7c478bd9Sstevel@tonic-gate 		if ((mp = zmp) == NULL)
663*7c478bd9Sstevel@tonic-gate 			goto msg_oerror;
664*7c478bd9Sstevel@tonic-gate 	}
665*7c478bd9Sstevel@tonic-gate 
666*7c478bd9Sstevel@tonic-gate 	/*
667*7c478bd9Sstevel@tonic-gate 	 * Do address/control and protocol compression if enabled.
668*7c478bd9Sstevel@tonic-gate 	 */
669*7c478bd9Sstevel@tonic-gate 	if (IS_COMP_AC(cp) && (proto != PPP_LCP)) {
670*7c478bd9Sstevel@tonic-gate 		mp->b_rptr += 2;	/* drop address & ctrl fields */
671*7c478bd9Sstevel@tonic-gate 		/*
672*7c478bd9Sstevel@tonic-gate 		 * Protocol field compression omits the first byte if
673*7c478bd9Sstevel@tonic-gate 		 * it would be 0x00, thus the check for < 0x100.
674*7c478bd9Sstevel@tonic-gate 		 */
675*7c478bd9Sstevel@tonic-gate 		if (proto < 0x100 && IS_COMP_PROT(cp)) {
676*7c478bd9Sstevel@tonic-gate 			++mp->b_rptr;	/* drop high protocol byte */
677*7c478bd9Sstevel@tonic-gate 		}
678*7c478bd9Sstevel@tonic-gate 	} else if ((proto < 0x100) && IS_COMP_PROT(cp)) {
679*7c478bd9Sstevel@tonic-gate 		/*
680*7c478bd9Sstevel@tonic-gate 		 * shuffle up the address & ctrl fields
681*7c478bd9Sstevel@tonic-gate 		 */
682*7c478bd9Sstevel@tonic-gate 		mp->b_rptr[2] = mp->b_rptr[1];
683*7c478bd9Sstevel@tonic-gate 		mp->b_rptr[1] = mp->b_rptr[0];
684*7c478bd9Sstevel@tonic-gate 		++mp->b_rptr;
685*7c478bd9Sstevel@tonic-gate 	}
686*7c478bd9Sstevel@tonic-gate 	mutex_enter(&cp->cp_pair_lock);
687*7c478bd9Sstevel@tonic-gate 	cp->cp_stats.ppp_opackets++;
688*7c478bd9Sstevel@tonic-gate 	cp->cp_stats.ppp_obytes += msgsize(mp);
689*7c478bd9Sstevel@tonic-gate 	mutex_exit(&cp->cp_pair_lock);
690*7c478bd9Sstevel@tonic-gate 
691*7c478bd9Sstevel@tonic-gate 	CPDEBUG((DBGSTART "send (%ld bytes) flags=0x%b\n",
692*7c478bd9Sstevel@tonic-gate 	    (IS_CP_HASUNIT(cp) ? cp->cp_unit : -1), msgsize(mp),
693*7c478bd9Sstevel@tonic-gate 	    cp->cp_flags, CP_FLAGSSTR));
694*7c478bd9Sstevel@tonic-gate 	return (mp);
695*7c478bd9Sstevel@tonic-gate 
696*7c478bd9Sstevel@tonic-gate msg_oerror:
697*7c478bd9Sstevel@tonic-gate 	mutex_enter(&cp->cp_pair_lock);
698*7c478bd9Sstevel@tonic-gate 	cp->cp_stats.ppp_oerrors++;
699*7c478bd9Sstevel@tonic-gate 	mutex_exit(&cp->cp_pair_lock);
700*7c478bd9Sstevel@tonic-gate 	(void) putnextctl1(RD(q), M_CTL, PPPCTL_OERROR);
701*7c478bd9Sstevel@tonic-gate 	return (NULL);
702*7c478bd9Sstevel@tonic-gate }
703*7c478bd9Sstevel@tonic-gate 
704*7c478bd9Sstevel@tonic-gate /*
705*7c478bd9Sstevel@tonic-gate  * spppcomp_inner_ioctl()
706*7c478bd9Sstevel@tonic-gate  *
707*7c478bd9Sstevel@tonic-gate  * MT-Perimeters:
708*7c478bd9Sstevel@tonic-gate  *    exclusive inner; queue pair lock held.
709*7c478bd9Sstevel@tonic-gate  *
710*7c478bd9Sstevel@tonic-gate  * Description:
711*7c478bd9Sstevel@tonic-gate  *	Called by spppcomp_ioctl to handle state-affecting ioctls.
712*7c478bd9Sstevel@tonic-gate  *	Returns -1 if caller should do putnext, 0 for miocack, or >0
713*7c478bd9Sstevel@tonic-gate  *	for miocnak.  Must *NOT* do putnext in this routine, since
714*7c478bd9Sstevel@tonic-gate  *	lock is held here.
715*7c478bd9Sstevel@tonic-gate  */
716*7c478bd9Sstevel@tonic-gate static int
717*7c478bd9Sstevel@tonic-gate spppcomp_inner_ioctl(queue_t *q, mblk_t *mp)
718*7c478bd9Sstevel@tonic-gate {
719*7c478bd9Sstevel@tonic-gate 	sppp_comp_t	*cp;
720*7c478bd9Sstevel@tonic-gate 	int		flags;
721*7c478bd9Sstevel@tonic-gate 	int		mask;
722*7c478bd9Sstevel@tonic-gate 	int		rc;
723*7c478bd9Sstevel@tonic-gate 	int		len;
724*7c478bd9Sstevel@tonic-gate 	int		cmd;
725*7c478bd9Sstevel@tonic-gate 	int		nxslots;
726*7c478bd9Sstevel@tonic-gate 	int		nrslots;
727*7c478bd9Sstevel@tonic-gate 	int		val;
728*7c478bd9Sstevel@tonic-gate 	uchar_t		*opt_data;
729*7c478bd9Sstevel@tonic-gate 	uint32_t	opt_len;
730*7c478bd9Sstevel@tonic-gate 	struct compressor **comp;
731*7c478bd9Sstevel@tonic-gate 	struct compressor *ccomp;
732*7c478bd9Sstevel@tonic-gate 	struct iocblk	*iop;
733*7c478bd9Sstevel@tonic-gate 	void		*xtemp;
734*7c478bd9Sstevel@tonic-gate 
735*7c478bd9Sstevel@tonic-gate 	ASSERT(q != NULL);
736*7c478bd9Sstevel@tonic-gate 	ASSERT(q->q_ptr != NULL);
737*7c478bd9Sstevel@tonic-gate 	cp = (sppp_comp_t *)q->q_ptr;
738*7c478bd9Sstevel@tonic-gate 	ASSERT(mp != NULL);
739*7c478bd9Sstevel@tonic-gate 	ASSERT(mp->b_rptr != NULL);
740*7c478bd9Sstevel@tonic-gate 
741*7c478bd9Sstevel@tonic-gate 	iop = (struct iocblk *)mp->b_rptr;
742*7c478bd9Sstevel@tonic-gate 	rc = EINVAL;
743*7c478bd9Sstevel@tonic-gate 	len = 0;
744*7c478bd9Sstevel@tonic-gate 	switch (iop->ioc_cmd) {
745*7c478bd9Sstevel@tonic-gate 	case PPPIO_CFLAGS:
746*7c478bd9Sstevel@tonic-gate 		if (iop->ioc_count != 2 * sizeof (uint32_t) ||
747*7c478bd9Sstevel@tonic-gate 		    mp->b_cont == NULL)
748*7c478bd9Sstevel@tonic-gate 			break;
749*7c478bd9Sstevel@tonic-gate 
750*7c478bd9Sstevel@tonic-gate 		flags = ((uint32_t *)mp->b_cont->b_rptr)[0];
751*7c478bd9Sstevel@tonic-gate 		mask = ((uint32_t *)mp->b_cont->b_rptr)[1];
752*7c478bd9Sstevel@tonic-gate 
753*7c478bd9Sstevel@tonic-gate 		cp->cp_flags = (cp->cp_flags & ~mask) | (flags & mask);
754*7c478bd9Sstevel@tonic-gate 
755*7c478bd9Sstevel@tonic-gate 		if ((mask & CCP_ISOPEN) && (flags & CCP_ISOPEN) == 0) {
756*7c478bd9Sstevel@tonic-gate 			if (cp->cp_xstate != NULL) {
757*7c478bd9Sstevel@tonic-gate 				(*cp->cp_xcomp->comp_free)(cp->cp_xstate);
758*7c478bd9Sstevel@tonic-gate 				cp->cp_xstate = NULL;
759*7c478bd9Sstevel@tonic-gate 			}
760*7c478bd9Sstevel@tonic-gate 			if (cp->cp_rstate != NULL) {
761*7c478bd9Sstevel@tonic-gate 				(*cp->cp_rcomp->decomp_free)(cp->cp_rstate);
762*7c478bd9Sstevel@tonic-gate 				cp->cp_rstate = NULL;
763*7c478bd9Sstevel@tonic-gate 			}
764*7c478bd9Sstevel@tonic-gate 			cp->cp_flags &= ~CCP_ISUP;
765*7c478bd9Sstevel@tonic-gate 		}
766*7c478bd9Sstevel@tonic-gate 
767*7c478bd9Sstevel@tonic-gate 		CPDEBUG((DBGSTART
768*7c478bd9Sstevel@tonic-gate 		    "PPPIO_CFLAGS xflags=0x%b xmask=0x%b flags=0x%b\n",
769*7c478bd9Sstevel@tonic-gate 		    (IS_CP_HASUNIT(cp) ? cp->cp_unit : -1),
770*7c478bd9Sstevel@tonic-gate 		    flags, CP_FLAGSSTR, mask,
771*7c478bd9Sstevel@tonic-gate 		    CP_FLAGSSTR, cp->cp_flags, CP_FLAGSSTR));
772*7c478bd9Sstevel@tonic-gate 
773*7c478bd9Sstevel@tonic-gate 		/* If we're not the last PPP-speaker, then pass along. */
774*7c478bd9Sstevel@tonic-gate 		if (!IS_CP_LASTMOD(cp)) {
775*7c478bd9Sstevel@tonic-gate 			return (-1);	/* putnext */
776*7c478bd9Sstevel@tonic-gate 		}
777*7c478bd9Sstevel@tonic-gate 
778*7c478bd9Sstevel@tonic-gate 		*(uint32_t *)mp->b_cont->b_rptr = cp->cp_flags;
779*7c478bd9Sstevel@tonic-gate 		len = sizeof (uint32_t);
780*7c478bd9Sstevel@tonic-gate 		rc = 0;
781*7c478bd9Sstevel@tonic-gate 		break;
782*7c478bd9Sstevel@tonic-gate 
783*7c478bd9Sstevel@tonic-gate 	case PPPIO_VJINIT:
784*7c478bd9Sstevel@tonic-gate 		if (iop->ioc_count != 2 || mp->b_cont == NULL)
785*7c478bd9Sstevel@tonic-gate 			break;
786*7c478bd9Sstevel@tonic-gate 		/*
787*7c478bd9Sstevel@tonic-gate 		 * Even though it's not passed along, we have to
788*7c478bd9Sstevel@tonic-gate 		 * validate nrslots so that we don't agree to
789*7c478bd9Sstevel@tonic-gate 		 * decompress anything we cannot.
790*7c478bd9Sstevel@tonic-gate 		 */
791*7c478bd9Sstevel@tonic-gate 		nxslots = mp->b_cont->b_rptr[0] + 1;
792*7c478bd9Sstevel@tonic-gate 		nrslots = mp->b_cont->b_rptr[1] + 1;
793*7c478bd9Sstevel@tonic-gate 		if (nxslots > MAX_STATES || nrslots > MAX_STATES)
794*7c478bd9Sstevel@tonic-gate 			break;
795*7c478bd9Sstevel@tonic-gate 
796*7c478bd9Sstevel@tonic-gate 		/* No need to lock here; just reading a word is atomic */
797*7c478bd9Sstevel@tonic-gate 		/* mutex_enter(&cp->cp_pair_lock); */
798*7c478bd9Sstevel@tonic-gate 		cp->cp_vj_last_ierrors = cp->cp_stats.ppp_ierrors;
799*7c478bd9Sstevel@tonic-gate 		/* mutex_exit(&cp->cp_pair_lock); */
800*7c478bd9Sstevel@tonic-gate 		vj_compress_init(&cp->cp_vj, nxslots);
801*7c478bd9Sstevel@tonic-gate 		cp->cp_nxslots = nxslots;
802*7c478bd9Sstevel@tonic-gate 
803*7c478bd9Sstevel@tonic-gate 		CPDEBUG((DBGSTART
804*7c478bd9Sstevel@tonic-gate 		    "PPPIO_VJINIT txslots=%d rxslots=%d flags=0x%b\n",
805*7c478bd9Sstevel@tonic-gate 		    (IS_CP_HASUNIT(cp) ? cp->cp_unit : -1), nxslots,
806*7c478bd9Sstevel@tonic-gate 		    nrslots, cp->cp_flags, CP_FLAGSSTR));
807*7c478bd9Sstevel@tonic-gate 		rc = 0;
808*7c478bd9Sstevel@tonic-gate 		break;
809*7c478bd9Sstevel@tonic-gate 
810*7c478bd9Sstevel@tonic-gate 	case PPPIO_XCOMP:
811*7c478bd9Sstevel@tonic-gate 	case PPPIO_RCOMP:
812*7c478bd9Sstevel@tonic-gate 		if (iop->ioc_count < 2 || mp->b_cont == NULL)
813*7c478bd9Sstevel@tonic-gate 			break;
814*7c478bd9Sstevel@tonic-gate 		/*
815*7c478bd9Sstevel@tonic-gate 		 * The input data here is the raw CCP algorithm option
816*7c478bd9Sstevel@tonic-gate 		 * from negotiation.  The format is always one byte of
817*7c478bd9Sstevel@tonic-gate 		 * algorithm number, one byte of length, and
818*7c478bd9Sstevel@tonic-gate 		 * (length-2) bytes of algorithm-dependent data.  The
819*7c478bd9Sstevel@tonic-gate 		 * alloc routine is expected to parse and validate
820*7c478bd9Sstevel@tonic-gate 		 * this.
821*7c478bd9Sstevel@tonic-gate 		 */
822*7c478bd9Sstevel@tonic-gate 		opt_data = mp->b_cont->b_rptr;
823*7c478bd9Sstevel@tonic-gate 		opt_len = mp->b_cont->b_wptr - opt_data;
824*7c478bd9Sstevel@tonic-gate 		if (opt_len > iop->ioc_count) {
825*7c478bd9Sstevel@tonic-gate 			opt_len = iop->ioc_count;
826*7c478bd9Sstevel@tonic-gate 		}
827*7c478bd9Sstevel@tonic-gate 		len = mp->b_cont->b_rptr[1];
828*7c478bd9Sstevel@tonic-gate 		if (len < 2 || len > opt_len)
829*7c478bd9Sstevel@tonic-gate 			break;
830*7c478bd9Sstevel@tonic-gate 		len = 0;
831*7c478bd9Sstevel@tonic-gate 		for (comp = ppp_compressors; *comp != NULL; ++comp) {
832*7c478bd9Sstevel@tonic-gate 
833*7c478bd9Sstevel@tonic-gate 			if ((*comp)->compress_proto != opt_data[0]) {
834*7c478bd9Sstevel@tonic-gate 				continue;
835*7c478bd9Sstevel@tonic-gate 			}
836*7c478bd9Sstevel@tonic-gate 			rc = 0;
837*7c478bd9Sstevel@tonic-gate 			if (iop->ioc_cmd == PPPIO_XCOMP) {
838*7c478bd9Sstevel@tonic-gate 				/*
839*7c478bd9Sstevel@tonic-gate 				 * A previous call may have fetched
840*7c478bd9Sstevel@tonic-gate 				 * memory for a compressor that's now
841*7c478bd9Sstevel@tonic-gate 				 * being retired or reset.  Free it
842*7c478bd9Sstevel@tonic-gate 				 * using its mechanism for freeing
843*7c478bd9Sstevel@tonic-gate 				 * stuff.
844*7c478bd9Sstevel@tonic-gate 				 */
845*7c478bd9Sstevel@tonic-gate 				if ((xtemp = cp->cp_xstate) != NULL) {
846*7c478bd9Sstevel@tonic-gate 					cp->cp_xstate = NULL;
847*7c478bd9Sstevel@tonic-gate 					(*cp->cp_xcomp->comp_free)(xtemp);
848*7c478bd9Sstevel@tonic-gate 				}
849*7c478bd9Sstevel@tonic-gate 				cp->cp_xcomp = *comp;
850*7c478bd9Sstevel@tonic-gate 				cp->cp_xstate = (*comp)->comp_alloc(opt_data,
851*7c478bd9Sstevel@tonic-gate 				    opt_len);
852*7c478bd9Sstevel@tonic-gate 
853*7c478bd9Sstevel@tonic-gate 				if (cp->cp_xstate == NULL) {
854*7c478bd9Sstevel@tonic-gate 					rc = ENOSR;
855*7c478bd9Sstevel@tonic-gate 				}
856*7c478bd9Sstevel@tonic-gate 
857*7c478bd9Sstevel@tonic-gate 				CPDEBUG((DBGSTART "PPPIO_XCOMP opt_proto=0x%x "
858*7c478bd9Sstevel@tonic-gate 				    "opt_len=0x%d flags=0x%b\n",
859*7c478bd9Sstevel@tonic-gate 				    (IS_CP_HASUNIT(cp) ? cp->cp_unit : -1),
860*7c478bd9Sstevel@tonic-gate 				    (uchar_t)opt_data[0], opt_len,
861*7c478bd9Sstevel@tonic-gate 				    cp->cp_flags,
862*7c478bd9Sstevel@tonic-gate 				    CP_FLAGSSTR));
863*7c478bd9Sstevel@tonic-gate 			} else {
864*7c478bd9Sstevel@tonic-gate 				if ((xtemp = cp->cp_rstate) != NULL) {
865*7c478bd9Sstevel@tonic-gate 					cp->cp_rstate = NULL;
866*7c478bd9Sstevel@tonic-gate 					(*cp->cp_rcomp->decomp_free)(xtemp);
867*7c478bd9Sstevel@tonic-gate 				}
868*7c478bd9Sstevel@tonic-gate 				cp->cp_rcomp = *comp;
869*7c478bd9Sstevel@tonic-gate 				cp->cp_rstate =
870*7c478bd9Sstevel@tonic-gate 				    (*comp)->decomp_alloc(opt_data, opt_len);
871*7c478bd9Sstevel@tonic-gate 
872*7c478bd9Sstevel@tonic-gate 				if (cp->cp_rstate == NULL) {
873*7c478bd9Sstevel@tonic-gate 					rc = ENOSR;
874*7c478bd9Sstevel@tonic-gate 				}
875*7c478bd9Sstevel@tonic-gate 
876*7c478bd9Sstevel@tonic-gate 				CPDEBUG((DBGSTART "PPPIO_RCOMP opt_proto=0x%x "
877*7c478bd9Sstevel@tonic-gate 				    "opt_len=0x%d flags=0x%b\n",
878*7c478bd9Sstevel@tonic-gate 				    (IS_CP_HASUNIT(cp) ? cp->cp_unit : -1),
879*7c478bd9Sstevel@tonic-gate 				    (uchar_t)opt_data[0], opt_len,
880*7c478bd9Sstevel@tonic-gate 				    cp->cp_flags,
881*7c478bd9Sstevel@tonic-gate 				    CP_FLAGSSTR));
882*7c478bd9Sstevel@tonic-gate 			}
883*7c478bd9Sstevel@tonic-gate 			if (rc == 0 && (*comp)->set_effort != NULL) {
884*7c478bd9Sstevel@tonic-gate 				rc = (*(*comp)->set_effort)(cp->
885*7c478bd9Sstevel@tonic-gate 				    cp_xcomp == *comp ? cp->cp_xstate : NULL,
886*7c478bd9Sstevel@tonic-gate 				    cp->cp_rcomp == *comp ? cp->cp_rstate :
887*7c478bd9Sstevel@tonic-gate 				    NULL, cp->cp_effort);
888*7c478bd9Sstevel@tonic-gate 				if (rc != 0) {
889*7c478bd9Sstevel@tonic-gate 					CKDEBUG((DBGSTART
890*7c478bd9Sstevel@tonic-gate 					    "cannot set effort %d",
891*7c478bd9Sstevel@tonic-gate 					    cp->cp_unit, cp->cp_effort));
892*7c478bd9Sstevel@tonic-gate 					rc = 0;
893*7c478bd9Sstevel@tonic-gate 				}
894*7c478bd9Sstevel@tonic-gate 			}
895*7c478bd9Sstevel@tonic-gate 			break;
896*7c478bd9Sstevel@tonic-gate 		}
897*7c478bd9Sstevel@tonic-gate 		break;
898*7c478bd9Sstevel@tonic-gate 
899*7c478bd9Sstevel@tonic-gate 	case PPPIO_DEBUG:
900*7c478bd9Sstevel@tonic-gate 		if (iop->ioc_count != sizeof (uint32_t) || mp->b_cont == NULL)
901*7c478bd9Sstevel@tonic-gate 			break;
902*7c478bd9Sstevel@tonic-gate 
903*7c478bd9Sstevel@tonic-gate 		cmd = *(uint32_t *)mp->b_cont->b_rptr;
904*7c478bd9Sstevel@tonic-gate 
905*7c478bd9Sstevel@tonic-gate 		/* If it's not for us, then pass along. */
906*7c478bd9Sstevel@tonic-gate 		if (cmd != PPPDBG_LOG + PPPDBG_COMP) {
907*7c478bd9Sstevel@tonic-gate 			return (-1);	/* putnext */
908*7c478bd9Sstevel@tonic-gate 		}
909*7c478bd9Sstevel@tonic-gate 		cp->cp_flags |= CP_KDEBUG;
910*7c478bd9Sstevel@tonic-gate 
911*7c478bd9Sstevel@tonic-gate 		CKDEBUG((DBGSTART "PPPIO_DEBUG log enabled flags=0x%b\n",
912*7c478bd9Sstevel@tonic-gate 		    (IS_CP_HASUNIT(cp) ? cp->cp_unit : -1),
913*7c478bd9Sstevel@tonic-gate 		    cp->cp_flags, CP_FLAGSSTR));
914*7c478bd9Sstevel@tonic-gate 		rc = 0;
915*7c478bd9Sstevel@tonic-gate 		break;
916*7c478bd9Sstevel@tonic-gate 
917*7c478bd9Sstevel@tonic-gate 	case PPPIO_LASTMOD:
918*7c478bd9Sstevel@tonic-gate 		cp->cp_flags |= CP_LASTMOD;
919*7c478bd9Sstevel@tonic-gate 		CPDEBUG((DBGSTART "PPPIO_LASTMOD last module flags=0x%b\n",
920*7c478bd9Sstevel@tonic-gate 		    (IS_CP_HASUNIT(cp) ? cp->cp_unit : -1),
921*7c478bd9Sstevel@tonic-gate 		    cp->cp_flags, CP_FLAGSSTR));
922*7c478bd9Sstevel@tonic-gate 		rc = 0;
923*7c478bd9Sstevel@tonic-gate 		break;
924*7c478bd9Sstevel@tonic-gate 
925*7c478bd9Sstevel@tonic-gate 	case PPPIO_COMPLEV:	/* set compression effort level */
926*7c478bd9Sstevel@tonic-gate 		if (iop->ioc_count != sizeof (uint32_t) || mp->b_cont == NULL)
927*7c478bd9Sstevel@tonic-gate 			break;
928*7c478bd9Sstevel@tonic-gate 		val = *(uint32_t *)mp->b_cont->b_rptr;
929*7c478bd9Sstevel@tonic-gate 		cp->cp_effort = val;
930*7c478bd9Sstevel@tonic-gate 		/* Silently ignore if compressor doesn't understand this. */
931*7c478bd9Sstevel@tonic-gate 		rc = 0;
932*7c478bd9Sstevel@tonic-gate 		if ((ccomp = cp->cp_xcomp) != NULL &&
933*7c478bd9Sstevel@tonic-gate 		    ccomp->set_effort != NULL) {
934*7c478bd9Sstevel@tonic-gate 			rc = (*ccomp->set_effort)(cp->cp_xstate,
935*7c478bd9Sstevel@tonic-gate 			    ccomp == cp->cp_rcomp ? cp->cp_rstate : NULL, val);
936*7c478bd9Sstevel@tonic-gate 			if (rc != 0)
937*7c478bd9Sstevel@tonic-gate 				break;
938*7c478bd9Sstevel@tonic-gate 		}
939*7c478bd9Sstevel@tonic-gate 		if ((ccomp = cp->cp_rcomp) != NULL && ccomp != cp->cp_xcomp &&
940*7c478bd9Sstevel@tonic-gate 		    ccomp->set_effort != NULL)
941*7c478bd9Sstevel@tonic-gate 			rc = (*ccomp->set_effort)(NULL, cp->cp_rstate, val);
942*7c478bd9Sstevel@tonic-gate 		break;
943*7c478bd9Sstevel@tonic-gate 	}
944*7c478bd9Sstevel@tonic-gate 	if (rc == 0 && mp->b_cont != NULL)
945*7c478bd9Sstevel@tonic-gate 		mp->b_cont->b_wptr = mp->b_cont->b_rptr + len;
946*7c478bd9Sstevel@tonic-gate 	return (rc);
947*7c478bd9Sstevel@tonic-gate }
948*7c478bd9Sstevel@tonic-gate 
949*7c478bd9Sstevel@tonic-gate /*
950*7c478bd9Sstevel@tonic-gate  * spppcomp_getcstat()
951*7c478bd9Sstevel@tonic-gate  *
952*7c478bd9Sstevel@tonic-gate  * MT-Perimeters:
953*7c478bd9Sstevel@tonic-gate  *    exclusive inner.
954*7c478bd9Sstevel@tonic-gate  *
955*7c478bd9Sstevel@tonic-gate  * Description:
956*7c478bd9Sstevel@tonic-gate  *    Called by spppcomp_ioctl as the result of receiving a PPPIO_GETCSTAT.
957*7c478bd9Sstevel@tonic-gate  */
958*7c478bd9Sstevel@tonic-gate static void
959*7c478bd9Sstevel@tonic-gate spppcomp_getcstat(queue_t *q, mblk_t *mp, sppp_comp_t *cp)
960*7c478bd9Sstevel@tonic-gate {
961*7c478bd9Sstevel@tonic-gate 	mblk_t		*mpnext;
962*7c478bd9Sstevel@tonic-gate 	struct ppp_comp_stats	*csp;
963*7c478bd9Sstevel@tonic-gate 
964*7c478bd9Sstevel@tonic-gate 	ASSERT(q != NULL);
965*7c478bd9Sstevel@tonic-gate 	ASSERT(q->q_ptr != NULL);
966*7c478bd9Sstevel@tonic-gate 	ASSERT(mp != NULL);
967*7c478bd9Sstevel@tonic-gate 	ASSERT(mp->b_rptr != NULL);
968*7c478bd9Sstevel@tonic-gate 	ASSERT(cp != NULL);
969*7c478bd9Sstevel@tonic-gate 
970*7c478bd9Sstevel@tonic-gate 	mpnext = allocb(sizeof (struct ppp_comp_stats), BPRI_MED);
971*7c478bd9Sstevel@tonic-gate 	if (mpnext == NULL) {
972*7c478bd9Sstevel@tonic-gate 		miocnak(q, mp, 0, ENOSR);
973*7c478bd9Sstevel@tonic-gate 		return;
974*7c478bd9Sstevel@tonic-gate 	}
975*7c478bd9Sstevel@tonic-gate 	if (mp->b_cont != NULL) {
976*7c478bd9Sstevel@tonic-gate 		freemsg(mp->b_cont);
977*7c478bd9Sstevel@tonic-gate 	}
978*7c478bd9Sstevel@tonic-gate 	mp->b_cont = mpnext;
979*7c478bd9Sstevel@tonic-gate 	csp = (struct ppp_comp_stats *)mpnext->b_wptr;
980*7c478bd9Sstevel@tonic-gate 	mpnext->b_wptr += sizeof (struct ppp_comp_stats);
981*7c478bd9Sstevel@tonic-gate 	bzero((caddr_t)csp, sizeof (struct ppp_comp_stats));
982*7c478bd9Sstevel@tonic-gate 
983*7c478bd9Sstevel@tonic-gate 	if (cp->cp_xstate != NULL) {
984*7c478bd9Sstevel@tonic-gate 		(*cp->cp_xcomp->comp_stat)(cp->cp_xstate, &csp->c);
985*7c478bd9Sstevel@tonic-gate 	}
986*7c478bd9Sstevel@tonic-gate 	if (cp->cp_rstate != NULL) {
987*7c478bd9Sstevel@tonic-gate 		(*cp->cp_rcomp->decomp_stat)(cp->cp_rstate, &csp->d);
988*7c478bd9Sstevel@tonic-gate 	}
989*7c478bd9Sstevel@tonic-gate 
990*7c478bd9Sstevel@tonic-gate 	miocack(q, mp, sizeof (struct ppp_comp_stats), 0);
991*7c478bd9Sstevel@tonic-gate }
992*7c478bd9Sstevel@tonic-gate 
993*7c478bd9Sstevel@tonic-gate /*
994*7c478bd9Sstevel@tonic-gate  * spppcomp_ioctl()
995*7c478bd9Sstevel@tonic-gate  *
996*7c478bd9Sstevel@tonic-gate  * MT-Perimeters:
997*7c478bd9Sstevel@tonic-gate  *    exclusive inner.
998*7c478bd9Sstevel@tonic-gate  *
999*7c478bd9Sstevel@tonic-gate  * Description:
1000*7c478bd9Sstevel@tonic-gate  *    Called by spppcomp_wput as the result of receiving an M_IOCTL
1001*7c478bd9Sstevel@tonic-gate  *    command.
1002*7c478bd9Sstevel@tonic-gate  */
1003*7c478bd9Sstevel@tonic-gate static void
1004*7c478bd9Sstevel@tonic-gate spppcomp_ioctl(queue_t *q, mblk_t *mp, sppp_comp_t *cp)
1005*7c478bd9Sstevel@tonic-gate {
1006*7c478bd9Sstevel@tonic-gate 	struct iocblk	*iop;
1007*7c478bd9Sstevel@tonic-gate 	int flag;
1008*7c478bd9Sstevel@tonic-gate 
1009*7c478bd9Sstevel@tonic-gate 	ASSERT(q != NULL);
1010*7c478bd9Sstevel@tonic-gate 	ASSERT(q->q_ptr != NULL);
1011*7c478bd9Sstevel@tonic-gate 	ASSERT(mp != NULL);
1012*7c478bd9Sstevel@tonic-gate 	ASSERT(mp->b_rptr != NULL);
1013*7c478bd9Sstevel@tonic-gate 	ASSERT(cp != NULL);
1014*7c478bd9Sstevel@tonic-gate 
1015*7c478bd9Sstevel@tonic-gate 	iop = (struct iocblk *)mp->b_rptr;
1016*7c478bd9Sstevel@tonic-gate 	switch (iop->ioc_cmd) {
1017*7c478bd9Sstevel@tonic-gate 	case PPPIO_CFLAGS:
1018*7c478bd9Sstevel@tonic-gate 	case PPPIO_VJINIT:
1019*7c478bd9Sstevel@tonic-gate 	case PPPIO_XCOMP:
1020*7c478bd9Sstevel@tonic-gate 	case PPPIO_RCOMP:
1021*7c478bd9Sstevel@tonic-gate 	case PPPIO_DEBUG:
1022*7c478bd9Sstevel@tonic-gate 	case PPPIO_LASTMOD:
1023*7c478bd9Sstevel@tonic-gate 	case PPPIO_COMPLEV:
1024*7c478bd9Sstevel@tonic-gate 		mutex_enter(&cp->cp_pair_lock);
1025*7c478bd9Sstevel@tonic-gate 		flag = spppcomp_inner_ioctl(q, mp);
1026*7c478bd9Sstevel@tonic-gate 		mutex_exit(&cp->cp_pair_lock);
1027*7c478bd9Sstevel@tonic-gate 		if (flag == -1) {
1028*7c478bd9Sstevel@tonic-gate 			putnext(q, mp);
1029*7c478bd9Sstevel@tonic-gate 		} else if (flag == 0) {
1030*7c478bd9Sstevel@tonic-gate 			miocack(q, mp,
1031*7c478bd9Sstevel@tonic-gate 			    mp->b_cont == NULL ? 0 : MBLKL(mp->b_cont), 0);
1032*7c478bd9Sstevel@tonic-gate 		} else {
1033*7c478bd9Sstevel@tonic-gate 			miocnak(q, mp, 0, flag);
1034*7c478bd9Sstevel@tonic-gate 		}
1035*7c478bd9Sstevel@tonic-gate 		break;
1036*7c478bd9Sstevel@tonic-gate 
1037*7c478bd9Sstevel@tonic-gate 	case PPPIO_GETCSTAT:
1038*7c478bd9Sstevel@tonic-gate 		spppcomp_getcstat(q, mp, cp);
1039*7c478bd9Sstevel@tonic-gate 		break;
1040*7c478bd9Sstevel@tonic-gate 
1041*7c478bd9Sstevel@tonic-gate 	case PPPIO_GTYPE:	/* get existing driver type */
1042*7c478bd9Sstevel@tonic-gate 		if (!IS_CP_LASTMOD(cp)) {
1043*7c478bd9Sstevel@tonic-gate 			putnext(q, mp);
1044*7c478bd9Sstevel@tonic-gate 			break;
1045*7c478bd9Sstevel@tonic-gate 		}
1046*7c478bd9Sstevel@tonic-gate 		freemsg(mp->b_next);
1047*7c478bd9Sstevel@tonic-gate 		mp->b_next = allocb(sizeof (uint32_t), BPRI_MED);
1048*7c478bd9Sstevel@tonic-gate 		if (mp->b_next == NULL) {
1049*7c478bd9Sstevel@tonic-gate 			miocnak(q, mp, 0, ENOSR);
1050*7c478bd9Sstevel@tonic-gate 		} else {
1051*7c478bd9Sstevel@tonic-gate 			*(uint32_t *)mp->b_cont->b_wptr = PPPTYP_HC;
1052*7c478bd9Sstevel@tonic-gate 			mp->b_cont->b_wptr += sizeof (uint32_t);
1053*7c478bd9Sstevel@tonic-gate 			miocack(q, mp, sizeof (uint32_t), 0);
1054*7c478bd9Sstevel@tonic-gate 		}
1055*7c478bd9Sstevel@tonic-gate 		break;
1056*7c478bd9Sstevel@tonic-gate 
1057*7c478bd9Sstevel@tonic-gate 	default:
1058*7c478bd9Sstevel@tonic-gate 		putnext(q, mp);
1059*7c478bd9Sstevel@tonic-gate 		break;
1060*7c478bd9Sstevel@tonic-gate 	}
1061*7c478bd9Sstevel@tonic-gate }
1062*7c478bd9Sstevel@tonic-gate 
1063*7c478bd9Sstevel@tonic-gate /*
1064*7c478bd9Sstevel@tonic-gate  * spppcomp_mctl()
1065*7c478bd9Sstevel@tonic-gate  *
1066*7c478bd9Sstevel@tonic-gate  * MT-Perimeters:
1067*7c478bd9Sstevel@tonic-gate  *    exclusive inner; queue pair lock held.
1068*7c478bd9Sstevel@tonic-gate  *
1069*7c478bd9Sstevel@tonic-gate  * Description:
1070*7c478bd9Sstevel@tonic-gate  *	Called by spppcomp_wput as the result of receiving an M_CTL
1071*7c478bd9Sstevel@tonic-gate  *	message from another STREAMS module, and returns non-zero if
1072*7c478bd9Sstevel@tonic-gate  *	caller should do putnext or zero for freemsg.  Must *NOT* do
1073*7c478bd9Sstevel@tonic-gate  *	putnext in this routine, since lock is held here.
1074*7c478bd9Sstevel@tonic-gate  */
1075*7c478bd9Sstevel@tonic-gate static int
1076*7c478bd9Sstevel@tonic-gate spppcomp_mctl(queue_t *q, mblk_t *mp)
1077*7c478bd9Sstevel@tonic-gate {
1078*7c478bd9Sstevel@tonic-gate 	sppp_comp_t		*cp;
1079*7c478bd9Sstevel@tonic-gate 	kstat_t			*ksp;
1080*7c478bd9Sstevel@tonic-gate 	char			unit[32];
1081*7c478bd9Sstevel@tonic-gate 	const char **cpp;
1082*7c478bd9Sstevel@tonic-gate 	kstat_named_t *knt;
1083*7c478bd9Sstevel@tonic-gate 
1084*7c478bd9Sstevel@tonic-gate 	ASSERT(q != NULL);
1085*7c478bd9Sstevel@tonic-gate 	ASSERT(q->q_ptr != NULL);
1086*7c478bd9Sstevel@tonic-gate 	cp = (sppp_comp_t *)q->q_ptr;
1087*7c478bd9Sstevel@tonic-gate 	ASSERT(mp != NULL);
1088*7c478bd9Sstevel@tonic-gate 	ASSERT(mp->b_rptr != NULL);
1089*7c478bd9Sstevel@tonic-gate 
1090*7c478bd9Sstevel@tonic-gate 	switch (*mp->b_rptr) {
1091*7c478bd9Sstevel@tonic-gate 	case PPPCTL_MTU:
1092*7c478bd9Sstevel@tonic-gate 		if (MBLKL(mp) < 4) {
1093*7c478bd9Sstevel@tonic-gate 			break;
1094*7c478bd9Sstevel@tonic-gate 		}
1095*7c478bd9Sstevel@tonic-gate 		cp->cp_mtu = ((ushort_t *)mp->b_rptr)[1];
1096*7c478bd9Sstevel@tonic-gate 
1097*7c478bd9Sstevel@tonic-gate 		CPDEBUG((DBGSTART "PPPCTL_MTU (%d) flags=0x%b\n",
1098*7c478bd9Sstevel@tonic-gate 		    (IS_CP_HASUNIT(cp) ? cp->cp_unit : -1),
1099*7c478bd9Sstevel@tonic-gate 		    cp->cp_mtu, cp->cp_flags, CP_FLAGSSTR));
1100*7c478bd9Sstevel@tonic-gate 		break;
1101*7c478bd9Sstevel@tonic-gate 	case PPPCTL_MRU:
1102*7c478bd9Sstevel@tonic-gate 		if (MBLKL(mp) < 4) {
1103*7c478bd9Sstevel@tonic-gate 			break;
1104*7c478bd9Sstevel@tonic-gate 		}
1105*7c478bd9Sstevel@tonic-gate 		cp->cp_mru = ((ushort_t *)mp->b_rptr)[1];
1106*7c478bd9Sstevel@tonic-gate 
1107*7c478bd9Sstevel@tonic-gate 		CPDEBUG((DBGSTART "PPPCTL_MRU (%d) flags=0x%b\n",
1108*7c478bd9Sstevel@tonic-gate 		    (IS_CP_HASUNIT(cp) ? cp->cp_unit : -1),
1109*7c478bd9Sstevel@tonic-gate 		    cp->cp_mru, cp->cp_flags, CP_FLAGSSTR));
1110*7c478bd9Sstevel@tonic-gate 		break;
1111*7c478bd9Sstevel@tonic-gate 	case PPPCTL_UNIT:
1112*7c478bd9Sstevel@tonic-gate 		if (MBLKL(mp) < 8) {
1113*7c478bd9Sstevel@tonic-gate 			break;
1114*7c478bd9Sstevel@tonic-gate 		}
1115*7c478bd9Sstevel@tonic-gate 		/* If PPPCTL_UNIT has already been issued, then ignore. */
1116*7c478bd9Sstevel@tonic-gate 		if (IS_CP_HASUNIT(cp)) {
1117*7c478bd9Sstevel@tonic-gate 			break;
1118*7c478bd9Sstevel@tonic-gate 		}
1119*7c478bd9Sstevel@tonic-gate 		ASSERT(cp->cp_kstats == NULL);
1120*7c478bd9Sstevel@tonic-gate 		cp->cp_unit = ((uint32_t *)mp->b_rptr)[1];
1121*7c478bd9Sstevel@tonic-gate 
1122*7c478bd9Sstevel@tonic-gate 		/* Create kstats for this unit. */
1123*7c478bd9Sstevel@tonic-gate 		(void) sprintf(unit, "%s%d", COMP_MOD_NAME, cp->cp_unit);
1124*7c478bd9Sstevel@tonic-gate 		ksp = kstat_create(COMP_MOD_NAME, cp->cp_unit, unit, "net",
1125*7c478bd9Sstevel@tonic-gate 			KSTAT_TYPE_NAMED, sizeof (spppcomp_kstats_t) /
1126*7c478bd9Sstevel@tonic-gate 			sizeof (kstat_named_t), 0);
1127*7c478bd9Sstevel@tonic-gate 
1128*7c478bd9Sstevel@tonic-gate 		if (ksp != NULL) {
1129*7c478bd9Sstevel@tonic-gate 			cp->cp_flags |= CP_HASUNIT;
1130*7c478bd9Sstevel@tonic-gate 			cp->cp_kstats = ksp;
1131*7c478bd9Sstevel@tonic-gate 
1132*7c478bd9Sstevel@tonic-gate 			knt = (kstat_named_t *)ksp->ks_data;
1133*7c478bd9Sstevel@tonic-gate 			for (cpp = kstats_names;
1134*7c478bd9Sstevel@tonic-gate 			    cpp < kstats_names + Dim(kstats_names); cpp++) {
1135*7c478bd9Sstevel@tonic-gate 				kstat_named_init(knt, (char *)*cpp,
1136*7c478bd9Sstevel@tonic-gate 				    KSTAT_DATA_UINT32);
1137*7c478bd9Sstevel@tonic-gate 				knt++;
1138*7c478bd9Sstevel@tonic-gate 			}
1139*7c478bd9Sstevel@tonic-gate 			for (cpp = kstats64_names;
1140*7c478bd9Sstevel@tonic-gate 			    cpp < kstats64_names + Dim(kstats64_names); cpp++) {
1141*7c478bd9Sstevel@tonic-gate 				kstat_named_init(knt, (char *)*cpp,
1142*7c478bd9Sstevel@tonic-gate 				    KSTAT_DATA_UINT64);
1143*7c478bd9Sstevel@tonic-gate 				knt++;
1144*7c478bd9Sstevel@tonic-gate 			}
1145*7c478bd9Sstevel@tonic-gate 			ksp->ks_update = spppcomp_kstat_update;
1146*7c478bd9Sstevel@tonic-gate 			ksp->ks_private = (void *)cp;
1147*7c478bd9Sstevel@tonic-gate 			kstat_install(ksp);
1148*7c478bd9Sstevel@tonic-gate 
1149*7c478bd9Sstevel@tonic-gate 			CPDEBUG((DBGSTART "PPPCTL_UNIT flags=0x%b\n",
1150*7c478bd9Sstevel@tonic-gate 			    cp->cp_unit, cp->cp_flags, CP_FLAGSSTR));
1151*7c478bd9Sstevel@tonic-gate 		}
1152*7c478bd9Sstevel@tonic-gate 		break;
1153*7c478bd9Sstevel@tonic-gate 
1154*7c478bd9Sstevel@tonic-gate 	default:
1155*7c478bd9Sstevel@tonic-gate 		/* Forward unknown M_CTL messages along */
1156*7c478bd9Sstevel@tonic-gate 		return (1);
1157*7c478bd9Sstevel@tonic-gate 	}
1158*7c478bd9Sstevel@tonic-gate 
1159*7c478bd9Sstevel@tonic-gate 	/*
1160*7c478bd9Sstevel@tonic-gate 	 * For known PPP M_CTL messages, forward along only if we're not the
1161*7c478bd9Sstevel@tonic-gate 	 * last PPP-aware module.
1162*7c478bd9Sstevel@tonic-gate 	 */
1163*7c478bd9Sstevel@tonic-gate 	if (IS_CP_LASTMOD(cp))
1164*7c478bd9Sstevel@tonic-gate 		return (0);
1165*7c478bd9Sstevel@tonic-gate 	return (1);
1166*7c478bd9Sstevel@tonic-gate }
1167*7c478bd9Sstevel@tonic-gate 
1168*7c478bd9Sstevel@tonic-gate /*
1169*7c478bd9Sstevel@tonic-gate  * spppcomp_rput()
1170*7c478bd9Sstevel@tonic-gate  *
1171*7c478bd9Sstevel@tonic-gate  * MT-Perimeters:
1172*7c478bd9Sstevel@tonic-gate  *    exclusive inner.
1173*7c478bd9Sstevel@tonic-gate  *
1174*7c478bd9Sstevel@tonic-gate  * Description:
1175*7c478bd9Sstevel@tonic-gate  *    Upper read-side put procedure.  Messages get here from below.
1176*7c478bd9Sstevel@tonic-gate  *
1177*7c478bd9Sstevel@tonic-gate  *	The data handling logic is a little more tricky here.  We
1178*7c478bd9Sstevel@tonic-gate  *	defer to the service routine if q_first isn't NULL (to
1179*7c478bd9Sstevel@tonic-gate  *	preserve message ordering after deferring a previous message),
1180*7c478bd9Sstevel@tonic-gate  *	bcanputnext() is FALSE (to handle flow control), or we have
1181*7c478bd9Sstevel@tonic-gate  *	done a lot of processing recently and we're about to do a lot
1182*7c478bd9Sstevel@tonic-gate  *	more and we're in an interrupt context (on the theory that
1183*7c478bd9Sstevel@tonic-gate  *	we're hogging the CPU in this case).
1184*7c478bd9Sstevel@tonic-gate  */
1185*7c478bd9Sstevel@tonic-gate static int
1186*7c478bd9Sstevel@tonic-gate spppcomp_rput(queue_t *q, mblk_t *mp)
1187*7c478bd9Sstevel@tonic-gate {
1188*7c478bd9Sstevel@tonic-gate 	sppp_comp_t		*cp;
1189*7c478bd9Sstevel@tonic-gate 	struct iocblk		*iop;
1190*7c478bd9Sstevel@tonic-gate 	struct ppp_stats64	*psp;
1191*7c478bd9Sstevel@tonic-gate 	boolean_t		inter;
1192*7c478bd9Sstevel@tonic-gate 	hrtime_t		curtime;
1193*7c478bd9Sstevel@tonic-gate 
1194*7c478bd9Sstevel@tonic-gate 	ASSERT(q != NULL);
1195*7c478bd9Sstevel@tonic-gate 	ASSERT(q->q_ptr != NULL);
1196*7c478bd9Sstevel@tonic-gate 	cp = (sppp_comp_t *)q->q_ptr;
1197*7c478bd9Sstevel@tonic-gate 	ASSERT(mp != NULL);
1198*7c478bd9Sstevel@tonic-gate 
1199*7c478bd9Sstevel@tonic-gate 	switch (MTYPE(mp)) {
1200*7c478bd9Sstevel@tonic-gate 	case M_DATA:
1201*7c478bd9Sstevel@tonic-gate 		inter = servicing_interrupt();
1202*7c478bd9Sstevel@tonic-gate 		if (inter) {
1203*7c478bd9Sstevel@tonic-gate 			curtime = gethrtime();
1204*7c478bd9Sstevel@tonic-gate 
1205*7c478bd9Sstevel@tonic-gate 			/*
1206*7c478bd9Sstevel@tonic-gate 			 * If little time has passed since last
1207*7c478bd9Sstevel@tonic-gate 			 * arrival, then bump the counter.
1208*7c478bd9Sstevel@tonic-gate 			 */
1209*7c478bd9Sstevel@tonic-gate 			if (curtime - cp->cp_lastfinish < spppcomp_min_arrival)
1210*7c478bd9Sstevel@tonic-gate 				cp->cp_fastin++;
1211*7c478bd9Sstevel@tonic-gate 			else
1212*7c478bd9Sstevel@tonic-gate 				cp->cp_fastin >>= 1;	/* a guess */
1213*7c478bd9Sstevel@tonic-gate 		}
1214*7c478bd9Sstevel@tonic-gate 		/*
1215*7c478bd9Sstevel@tonic-gate 		 * If we're not decompressing, then we'll be fast, so
1216*7c478bd9Sstevel@tonic-gate 		 * we don't have to worry about hogging here.  If we
1217*7c478bd9Sstevel@tonic-gate 		 * are decompressing, then we have to check the
1218*7c478bd9Sstevel@tonic-gate 		 * cp_fastin count.
1219*7c478bd9Sstevel@tonic-gate 		 */
1220*7c478bd9Sstevel@tonic-gate 		if ((!(cp->cp_flags & (CCP_DECOMP_RUN | DECOMP_VJC)) ||
1221*7c478bd9Sstevel@tonic-gate 		    cp->cp_fastin < MAX_FAST_ARRIVALS) &&
1222*7c478bd9Sstevel@tonic-gate 		    q->q_first == NULL && bcanputnext(q, mp->b_band)) {
1223*7c478bd9Sstevel@tonic-gate #ifdef SPC_DEBUG
1224*7c478bd9Sstevel@tonic-gate 			cp->cp_in_handled++;
1225*7c478bd9Sstevel@tonic-gate #endif
1226*7c478bd9Sstevel@tonic-gate 			if ((mp = spppcomp_inpkt(q, mp)) != NULL)
1227*7c478bd9Sstevel@tonic-gate 				putnext(q, mp);
1228*7c478bd9Sstevel@tonic-gate 			if (inter) {
1229*7c478bd9Sstevel@tonic-gate 				cp->cp_lastfinish = gethrtime();
1230*7c478bd9Sstevel@tonic-gate 			}
1231*7c478bd9Sstevel@tonic-gate 		} else {
1232*7c478bd9Sstevel@tonic-gate 			/* Deferring; give him a clean slate */
1233*7c478bd9Sstevel@tonic-gate 			cp->cp_fastin = 0;
1234*7c478bd9Sstevel@tonic-gate #ifdef SPC_DEBUG
1235*7c478bd9Sstevel@tonic-gate 			cp->cp_in_queued++;
1236*7c478bd9Sstevel@tonic-gate #endif
1237*7c478bd9Sstevel@tonic-gate 			(void) putq(q, mp);
1238*7c478bd9Sstevel@tonic-gate 		}
1239*7c478bd9Sstevel@tonic-gate 		break;
1240*7c478bd9Sstevel@tonic-gate 	case M_IOCACK:
1241*7c478bd9Sstevel@tonic-gate 		iop = (struct iocblk *)mp->b_rptr;
1242*7c478bd9Sstevel@tonic-gate 		ASSERT(iop != NULL);
1243*7c478bd9Sstevel@tonic-gate 		/*
1244*7c478bd9Sstevel@tonic-gate 		 * Bundled with pppstats; no need to handle PPPIO_GETSTAT
1245*7c478bd9Sstevel@tonic-gate 		 * here since we'll never see it.
1246*7c478bd9Sstevel@tonic-gate 		 */
1247*7c478bd9Sstevel@tonic-gate 		if (iop->ioc_cmd == PPPIO_GETSTAT64 &&
1248*7c478bd9Sstevel@tonic-gate 		    iop->ioc_count == sizeof (struct ppp_stats64) &&
1249*7c478bd9Sstevel@tonic-gate 		    mp->b_cont != NULL) {
1250*7c478bd9Sstevel@tonic-gate 			/*
1251*7c478bd9Sstevel@tonic-gate 			 * This crock is to handle a badly-designed
1252*7c478bd9Sstevel@tonic-gate 			 * but well-known ioctl for ANU PPP.  Both
1253*7c478bd9Sstevel@tonic-gate 			 * link statistics and VJ statistics are
1254*7c478bd9Sstevel@tonic-gate 			 * requested together.
1255*7c478bd9Sstevel@tonic-gate 			 *
1256*7c478bd9Sstevel@tonic-gate 			 * Catch this on the way back from the
1257*7c478bd9Sstevel@tonic-gate 			 * spppasyn module so we can fill in the VJ
1258*7c478bd9Sstevel@tonic-gate 			 * stats.  This happens only when we have
1259*7c478bd9Sstevel@tonic-gate 			 * PPP-aware modules beneath us.
1260*7c478bd9Sstevel@tonic-gate 			 */
1261*7c478bd9Sstevel@tonic-gate 			psp = (struct ppp_stats64 *)mp->b_cont->b_rptr;
1262*7c478bd9Sstevel@tonic-gate 			psp->vj = cp->cp_vj.stats;
1263*7c478bd9Sstevel@tonic-gate 			CPDEBUG((DBGSTART
1264*7c478bd9Sstevel@tonic-gate 			    "PPPIO_GETSTAT64 (VJ filled) flags=0x%b\n",
1265*7c478bd9Sstevel@tonic-gate 			    (IS_CP_HASUNIT(cp) ? cp->cp_unit : -1),
1266*7c478bd9Sstevel@tonic-gate 			    cp->cp_flags, CP_FLAGSSTR));
1267*7c478bd9Sstevel@tonic-gate 		}
1268*7c478bd9Sstevel@tonic-gate 		putnext(q, mp);
1269*7c478bd9Sstevel@tonic-gate 		break;
1270*7c478bd9Sstevel@tonic-gate 	case M_CTL:
1271*7c478bd9Sstevel@tonic-gate 		/* Increase our statistics and forward it upstream. */
1272*7c478bd9Sstevel@tonic-gate 		mutex_enter(&cp->cp_pair_lock);
1273*7c478bd9Sstevel@tonic-gate 		if (*mp->b_rptr == PPPCTL_IERROR) {
1274*7c478bd9Sstevel@tonic-gate 			cp->cp_stats.ppp_ierrors++;
1275*7c478bd9Sstevel@tonic-gate 			cp->cp_ierr_low++;
1276*7c478bd9Sstevel@tonic-gate 		} else if (*mp->b_rptr == PPPCTL_OERROR) {
1277*7c478bd9Sstevel@tonic-gate 			cp->cp_stats.ppp_oerrors++;
1278*7c478bd9Sstevel@tonic-gate 			cp->cp_oerr_low++;
1279*7c478bd9Sstevel@tonic-gate 		}
1280*7c478bd9Sstevel@tonic-gate 		mutex_exit(&cp->cp_pair_lock);
1281*7c478bd9Sstevel@tonic-gate 		putnext(q, mp);
1282*7c478bd9Sstevel@tonic-gate 		break;
1283*7c478bd9Sstevel@tonic-gate 
1284*7c478bd9Sstevel@tonic-gate 	case M_FLUSH:
1285*7c478bd9Sstevel@tonic-gate 		CPDEBUG((DBGSTART "rput M_FLUSH (0x%x) flags=0x%b\n",
1286*7c478bd9Sstevel@tonic-gate 		    (IS_CP_HASUNIT(cp) ? cp->cp_unit : -1),
1287*7c478bd9Sstevel@tonic-gate 		    *mp->b_rptr, cp->cp_flags,	CP_FLAGSSTR));
1288*7c478bd9Sstevel@tonic-gate 		/*
1289*7c478bd9Sstevel@tonic-gate 		 * Just discard pending data.  For CCP, any
1290*7c478bd9Sstevel@tonic-gate 		 * decompressor dictionary sequencing problems caused
1291*7c478bd9Sstevel@tonic-gate 		 * by this will have to be handled by the compression
1292*7c478bd9Sstevel@tonic-gate 		 * protocol in use.  For VJ, we need to give the
1293*7c478bd9Sstevel@tonic-gate 		 * decompressor a heads-up.
1294*7c478bd9Sstevel@tonic-gate 		 */
1295*7c478bd9Sstevel@tonic-gate 		if (*mp->b_rptr & FLUSHR) {
1296*7c478bd9Sstevel@tonic-gate 			mutex_enter(&cp->cp_pair_lock);
1297*7c478bd9Sstevel@tonic-gate 			flushq(q, FLUSHDATA);
1298*7c478bd9Sstevel@tonic-gate 			cp->cp_vj_last_ierrors = cp->cp_stats.ppp_ierrors;
1299*7c478bd9Sstevel@tonic-gate 			vj_uncompress_err(&cp->cp_vj);
1300*7c478bd9Sstevel@tonic-gate 			mutex_exit(&cp->cp_pair_lock);
1301*7c478bd9Sstevel@tonic-gate 		}
1302*7c478bd9Sstevel@tonic-gate 		putnext(q, mp);
1303*7c478bd9Sstevel@tonic-gate 		break;
1304*7c478bd9Sstevel@tonic-gate 
1305*7c478bd9Sstevel@tonic-gate 	default:
1306*7c478bd9Sstevel@tonic-gate 		putnext(q, mp);
1307*7c478bd9Sstevel@tonic-gate 		break;
1308*7c478bd9Sstevel@tonic-gate 	}
1309*7c478bd9Sstevel@tonic-gate 	return (0);
1310*7c478bd9Sstevel@tonic-gate }
1311*7c478bd9Sstevel@tonic-gate 
1312*7c478bd9Sstevel@tonic-gate /*
1313*7c478bd9Sstevel@tonic-gate  * spppcomp_rsrv()
1314*7c478bd9Sstevel@tonic-gate  *
1315*7c478bd9Sstevel@tonic-gate  * MT-Perimeters:
1316*7c478bd9Sstevel@tonic-gate  *    exclusive inner.
1317*7c478bd9Sstevel@tonic-gate  *
1318*7c478bd9Sstevel@tonic-gate  * Description:
1319*7c478bd9Sstevel@tonic-gate  *    Upper read-side service procedure.  We handle data deferred from
1320*7c478bd9Sstevel@tonic-gate  *    spppcomp_rput here.
1321*7c478bd9Sstevel@tonic-gate  *
1322*7c478bd9Sstevel@tonic-gate  *	The data on the queue are always compressed (unprocessed).
1323*7c478bd9Sstevel@tonic-gate  *	The rput procedure tries to do decompression, but if it can't,
1324*7c478bd9Sstevel@tonic-gate  *	it will put the unprocessed data on the queue for later
1325*7c478bd9Sstevel@tonic-gate  *	handling.
1326*7c478bd9Sstevel@tonic-gate  */
1327*7c478bd9Sstevel@tonic-gate static int
1328*7c478bd9Sstevel@tonic-gate spppcomp_rsrv(queue_t *q)
1329*7c478bd9Sstevel@tonic-gate {
1330*7c478bd9Sstevel@tonic-gate 	mblk_t		*mp;
1331*7c478bd9Sstevel@tonic-gate 
1332*7c478bd9Sstevel@tonic-gate 	ASSERT(q != NULL);
1333*7c478bd9Sstevel@tonic-gate 	ASSERT(q->q_ptr != NULL);
1334*7c478bd9Sstevel@tonic-gate 
1335*7c478bd9Sstevel@tonic-gate 	while ((mp = getq(q)) != NULL) {
1336*7c478bd9Sstevel@tonic-gate 		/* We should only place M_DATA on the service queue. */
1337*7c478bd9Sstevel@tonic-gate 		ASSERT(MTYPE(mp) == M_DATA);
1338*7c478bd9Sstevel@tonic-gate 		/*
1339*7c478bd9Sstevel@tonic-gate 		 * If the module above us is flow-controlled, then put
1340*7c478bd9Sstevel@tonic-gate 		 * this message back on the queue again.
1341*7c478bd9Sstevel@tonic-gate 		 */
1342*7c478bd9Sstevel@tonic-gate 		if (!bcanputnext(q, mp->b_band)) {
1343*7c478bd9Sstevel@tonic-gate 			(void) putbq(q, mp);
1344*7c478bd9Sstevel@tonic-gate 			break;
1345*7c478bd9Sstevel@tonic-gate 		}
1346*7c478bd9Sstevel@tonic-gate 		if ((mp = spppcomp_inpkt(q, mp)) != NULL)
1347*7c478bd9Sstevel@tonic-gate 			putnext(q, mp);
1348*7c478bd9Sstevel@tonic-gate 	}
1349*7c478bd9Sstevel@tonic-gate 	return (0);
1350*7c478bd9Sstevel@tonic-gate }
1351*7c478bd9Sstevel@tonic-gate 
1352*7c478bd9Sstevel@tonic-gate /*
1353*7c478bd9Sstevel@tonic-gate  * spppcomp_inpkt()
1354*7c478bd9Sstevel@tonic-gate  *
1355*7c478bd9Sstevel@tonic-gate  * MT-Perimeters:
1356*7c478bd9Sstevel@tonic-gate  *    exclusive inner
1357*7c478bd9Sstevel@tonic-gate  *
1358*7c478bd9Sstevel@tonic-gate  * Description:
1359*7c478bd9Sstevel@tonic-gate  *    Process incoming packet.
1360*7c478bd9Sstevel@tonic-gate  */
1361*7c478bd9Sstevel@tonic-gate static mblk_t *
1362*7c478bd9Sstevel@tonic-gate spppcomp_inpkt(queue_t *q, mblk_t *mp)
1363*7c478bd9Sstevel@tonic-gate {
1364*7c478bd9Sstevel@tonic-gate 	ushort_t	proto;
1365*7c478bd9Sstevel@tonic-gate 	int		i;
1366*7c478bd9Sstevel@tonic-gate 	mblk_t		*zmp;
1367*7c478bd9Sstevel@tonic-gate 	mblk_t		*np;
1368*7c478bd9Sstevel@tonic-gate 	uchar_t		*dp;
1369*7c478bd9Sstevel@tonic-gate 	int		len;
1370*7c478bd9Sstevel@tonic-gate 	int		hlen;
1371*7c478bd9Sstevel@tonic-gate 	sppp_comp_t	*cp;
1372*7c478bd9Sstevel@tonic-gate 
1373*7c478bd9Sstevel@tonic-gate 	ASSERT(q != NULL);
1374*7c478bd9Sstevel@tonic-gate 	ASSERT(mp != NULL);
1375*7c478bd9Sstevel@tonic-gate 	cp = (sppp_comp_t *)q->q_ptr;
1376*7c478bd9Sstevel@tonic-gate 	ASSERT(cp != NULL);
1377*7c478bd9Sstevel@tonic-gate 
1378*7c478bd9Sstevel@tonic-gate 	len = msgsize(mp);
1379*7c478bd9Sstevel@tonic-gate 
1380*7c478bd9Sstevel@tonic-gate 	mutex_enter(&cp->cp_pair_lock);
1381*7c478bd9Sstevel@tonic-gate 	cp->cp_stats.ppp_ibytes += len;
1382*7c478bd9Sstevel@tonic-gate 	cp->cp_stats.ppp_ipackets++;
1383*7c478bd9Sstevel@tonic-gate 	mutex_exit(&cp->cp_pair_lock);
1384*7c478bd9Sstevel@tonic-gate 	/*
1385*7c478bd9Sstevel@tonic-gate 	 * First work out the protocol and where the PPP header ends.
1386*7c478bd9Sstevel@tonic-gate 	 */
1387*7c478bd9Sstevel@tonic-gate 	i = 0;
1388*7c478bd9Sstevel@tonic-gate 	proto = MSG_BYTE(mp, 0);
1389*7c478bd9Sstevel@tonic-gate 	if (proto == PPP_ALLSTATIONS) {
1390*7c478bd9Sstevel@tonic-gate 		i = 2;
1391*7c478bd9Sstevel@tonic-gate 		proto = MSG_BYTE(mp, 2);
1392*7c478bd9Sstevel@tonic-gate 	}
1393*7c478bd9Sstevel@tonic-gate 	if ((proto & 1) == 0) {
1394*7c478bd9Sstevel@tonic-gate 		++i;
1395*7c478bd9Sstevel@tonic-gate 		proto = (proto << 8) + MSG_BYTE(mp, i);
1396*7c478bd9Sstevel@tonic-gate 	}
1397*7c478bd9Sstevel@tonic-gate 	hlen = i + 1;
1398*7c478bd9Sstevel@tonic-gate 	/*
1399*7c478bd9Sstevel@tonic-gate 	 * Now reconstruct a complete, contiguous PPP header at the
1400*7c478bd9Sstevel@tonic-gate 	 * start of the packet.
1401*7c478bd9Sstevel@tonic-gate 	 */
1402*7c478bd9Sstevel@tonic-gate 	if (hlen < (IS_DECOMP_AC(cp) ? 0 : 2) + (IS_DECOMP_PROT(cp) ? 1 : 2)) {
1403*7c478bd9Sstevel@tonic-gate 		/* count these? */
1404*7c478bd9Sstevel@tonic-gate 		goto bad;
1405*7c478bd9Sstevel@tonic-gate 	}
1406*7c478bd9Sstevel@tonic-gate 	if (mp->b_rptr + hlen > mp->b_wptr) {
1407*7c478bd9Sstevel@tonic-gate 		/*
1408*7c478bd9Sstevel@tonic-gate 		 * Header is known to be intact here; so adjmsg will do the
1409*7c478bd9Sstevel@tonic-gate 		 * right thing here.
1410*7c478bd9Sstevel@tonic-gate 		 */
1411*7c478bd9Sstevel@tonic-gate 		if (!adjmsg(mp, hlen)) {
1412*7c478bd9Sstevel@tonic-gate 			goto bad;
1413*7c478bd9Sstevel@tonic-gate 		}
1414*7c478bd9Sstevel@tonic-gate 		hlen = 0;
1415*7c478bd9Sstevel@tonic-gate 	}
1416*7c478bd9Sstevel@tonic-gate 	if (hlen != PPP_HDRLEN) {
1417*7c478bd9Sstevel@tonic-gate 		/*
1418*7c478bd9Sstevel@tonic-gate 		 * We need to put some bytes on the front of the packet
1419*7c478bd9Sstevel@tonic-gate 		 * to make a full-length PPP header. If we can put them
1420*7c478bd9Sstevel@tonic-gate 		 * in mp, we do, otherwise we tack another mblk on the
1421*7c478bd9Sstevel@tonic-gate 		 * front.
1422*7c478bd9Sstevel@tonic-gate 		 *
1423*7c478bd9Sstevel@tonic-gate 		 * XXX we really shouldn't need to carry around the address
1424*7c478bd9Sstevel@tonic-gate 		 * and control at this stage.  ACFC and PFC need to be
1425*7c478bd9Sstevel@tonic-gate 		 * reworked.
1426*7c478bd9Sstevel@tonic-gate 		 */
1427*7c478bd9Sstevel@tonic-gate 		dp = mp->b_rptr + hlen - PPP_HDRLEN;
1428*7c478bd9Sstevel@tonic-gate 		if ((dp < mp->b_datap->db_base) || (DB_REF(mp) > 1)) {
1429*7c478bd9Sstevel@tonic-gate 
1430*7c478bd9Sstevel@tonic-gate 			np = allocb(PPP_HDRLEN, BPRI_MED);
1431*7c478bd9Sstevel@tonic-gate 			if (np == 0) {
1432*7c478bd9Sstevel@tonic-gate 				goto bad;
1433*7c478bd9Sstevel@tonic-gate 			}
1434*7c478bd9Sstevel@tonic-gate 			np->b_cont = mp;
1435*7c478bd9Sstevel@tonic-gate 			mp->b_rptr += hlen;
1436*7c478bd9Sstevel@tonic-gate 			mp = np;
1437*7c478bd9Sstevel@tonic-gate 			dp = mp->b_wptr;
1438*7c478bd9Sstevel@tonic-gate 			mp->b_wptr += PPP_HDRLEN;
1439*7c478bd9Sstevel@tonic-gate 		} else {
1440*7c478bd9Sstevel@tonic-gate 			mp->b_rptr = dp;
1441*7c478bd9Sstevel@tonic-gate 		}
1442*7c478bd9Sstevel@tonic-gate 		dp[0] = PPP_ALLSTATIONS;
1443*7c478bd9Sstevel@tonic-gate 		dp[1] = PPP_UI;
1444*7c478bd9Sstevel@tonic-gate 		dp[2] = (proto >> 8) & 0xff;
1445*7c478bd9Sstevel@tonic-gate 		dp[3] = proto & 0xff;
1446*7c478bd9Sstevel@tonic-gate 	}
1447*7c478bd9Sstevel@tonic-gate 	/*
1448*7c478bd9Sstevel@tonic-gate 	 * Now see if we have a compressed packet to decompress, or a
1449*7c478bd9Sstevel@tonic-gate 	 * CCP negotiation packet to take notice of.  It's guaranteed
1450*7c478bd9Sstevel@tonic-gate 	 * that at least PPP_HDRLEN bytes are contiguous in the first
1451*7c478bd9Sstevel@tonic-gate 	 * block now.
1452*7c478bd9Sstevel@tonic-gate 	 */
1453*7c478bd9Sstevel@tonic-gate 	proto = PPP_PROTOCOL(mp->b_rptr);
1454*7c478bd9Sstevel@tonic-gate 	if (proto == PPP_CCP) {
1455*7c478bd9Sstevel@tonic-gate 		len = msgsize(mp);
1456*7c478bd9Sstevel@tonic-gate 		if (mp->b_wptr < mp->b_rptr + len) {
1457*7c478bd9Sstevel@tonic-gate #ifdef SPC_DEBUG
1458*7c478bd9Sstevel@tonic-gate 			mutex_enter(&cp->cp_pair_lock);
1459*7c478bd9Sstevel@tonic-gate 			cp->cp_imsg_ccp_pull++;
1460*7c478bd9Sstevel@tonic-gate 			mutex_exit(&cp->cp_pair_lock);
1461*7c478bd9Sstevel@tonic-gate #endif
1462*7c478bd9Sstevel@tonic-gate 			zmp = msgpullup(mp, len);
1463*7c478bd9Sstevel@tonic-gate 			freemsg(mp);
1464*7c478bd9Sstevel@tonic-gate 			mp = zmp;
1465*7c478bd9Sstevel@tonic-gate 			if (mp == 0) {
1466*7c478bd9Sstevel@tonic-gate 				goto bad;
1467*7c478bd9Sstevel@tonic-gate 			}
1468*7c478bd9Sstevel@tonic-gate 		}
1469*7c478bd9Sstevel@tonic-gate 		mutex_enter(&cp->cp_pair_lock);
1470*7c478bd9Sstevel@tonic-gate 		comp_ccp(q, mp, cp, B_TRUE);
1471*7c478bd9Sstevel@tonic-gate 		mutex_exit(&cp->cp_pair_lock);
1472*7c478bd9Sstevel@tonic-gate 	} else if ((cp->cp_flags & (CCP_ISUP | CCP_DECOMP_RUN | CCP_ERR)) ==
1473*7c478bd9Sstevel@tonic-gate 	    (CCP_ISUP | CCP_DECOMP_RUN) && cp->cp_rstate != NULL) {
1474*7c478bd9Sstevel@tonic-gate 		int	rv;
1475*7c478bd9Sstevel@tonic-gate 
1476*7c478bd9Sstevel@tonic-gate 		if ((proto == PPP_COMP) || (proto == PPP_COMPFRAG)) {
1477*7c478bd9Sstevel@tonic-gate 			rv = (*cp->cp_rcomp->decompress)(cp->cp_rstate, &mp);
1478*7c478bd9Sstevel@tonic-gate 			switch (rv) {
1479*7c478bd9Sstevel@tonic-gate 			case DECOMP_OK:
1480*7c478bd9Sstevel@tonic-gate 				break;
1481*7c478bd9Sstevel@tonic-gate 			case DECOMP_ERROR:
1482*7c478bd9Sstevel@tonic-gate 				cp->cp_flags |= CCP_ERROR;
1483*7c478bd9Sstevel@tonic-gate 				mutex_enter(&cp->cp_pair_lock);
1484*7c478bd9Sstevel@tonic-gate 				++cp->cp_stats.ppp_ierrors;
1485*7c478bd9Sstevel@tonic-gate 				mutex_exit(&cp->cp_pair_lock);
1486*7c478bd9Sstevel@tonic-gate 				(void) putnextctl1(q, M_CTL, PPPCTL_IERROR);
1487*7c478bd9Sstevel@tonic-gate 				break;
1488*7c478bd9Sstevel@tonic-gate 			case DECOMP_FATALERROR:
1489*7c478bd9Sstevel@tonic-gate 				cp->cp_flags |= CCP_FATALERROR;
1490*7c478bd9Sstevel@tonic-gate 				mutex_enter(&cp->cp_pair_lock);
1491*7c478bd9Sstevel@tonic-gate 				++cp->cp_stats.ppp_ierrors;
1492*7c478bd9Sstevel@tonic-gate 				mutex_exit(&cp->cp_pair_lock);
1493*7c478bd9Sstevel@tonic-gate 				(void) putnextctl1(q, M_CTL, PPPCTL_IERROR);
1494*7c478bd9Sstevel@tonic-gate 				break;
1495*7c478bd9Sstevel@tonic-gate 			}
1496*7c478bd9Sstevel@tonic-gate 			if (mp == NULL) {
1497*7c478bd9Sstevel@tonic-gate 				/* Decompress failed; data are gone. */
1498*7c478bd9Sstevel@tonic-gate 				return (NULL);
1499*7c478bd9Sstevel@tonic-gate 			}
1500*7c478bd9Sstevel@tonic-gate 		} else {
1501*7c478bd9Sstevel@tonic-gate 			/*
1502*7c478bd9Sstevel@tonic-gate 			 * For RFCs 1977 and 1979 (BSD Compress and Deflate),
1503*7c478bd9Sstevel@tonic-gate 			 * the compressor should send incompressible data
1504*7c478bd9Sstevel@tonic-gate 			 * without encapsulation and the receiver must update
1505*7c478bd9Sstevel@tonic-gate 			 * its decompression dictionary as though this data
1506*7c478bd9Sstevel@tonic-gate 			 * were received and decompressed.  This keeps the
1507*7c478bd9Sstevel@tonic-gate 			 * dictionaries in sync.
1508*7c478bd9Sstevel@tonic-gate 			 */
1509*7c478bd9Sstevel@tonic-gate 			rv = (*cp->cp_rcomp->incomp)(cp->cp_rstate, mp);
1510*7c478bd9Sstevel@tonic-gate 			if (rv < 0) {
1511*7c478bd9Sstevel@tonic-gate 				cp->cp_flags |= CCP_FATALERROR;
1512*7c478bd9Sstevel@tonic-gate 				mutex_enter(&cp->cp_pair_lock);
1513*7c478bd9Sstevel@tonic-gate 				++cp->cp_stats.ppp_ierrors;
1514*7c478bd9Sstevel@tonic-gate 				mutex_exit(&cp->cp_pair_lock);
1515*7c478bd9Sstevel@tonic-gate 				(void) putnextctl1(q, M_CTL, PPPCTL_IERROR);
1516*7c478bd9Sstevel@tonic-gate 			}
1517*7c478bd9Sstevel@tonic-gate 		}
1518*7c478bd9Sstevel@tonic-gate 	}
1519*7c478bd9Sstevel@tonic-gate 	/*
1520*7c478bd9Sstevel@tonic-gate 	 * Now do VJ decompression.
1521*7c478bd9Sstevel@tonic-gate 	 */
1522*7c478bd9Sstevel@tonic-gate 	proto = PPP_PROTOCOL(mp->b_rptr);
1523*7c478bd9Sstevel@tonic-gate 	if ((proto == PPP_VJC_COMP) || (proto == PPP_VJC_UNCOMP)) {
1524*7c478bd9Sstevel@tonic-gate 
1525*7c478bd9Sstevel@tonic-gate 		len = msgsize(mp) - PPP_HDRLEN;
1526*7c478bd9Sstevel@tonic-gate 
1527*7c478bd9Sstevel@tonic-gate 		if (!IS_DECOMP_VJC(cp) || (len <= 0)) {
1528*7c478bd9Sstevel@tonic-gate 			goto bad;
1529*7c478bd9Sstevel@tonic-gate 		}
1530*7c478bd9Sstevel@tonic-gate 		/*
1531*7c478bd9Sstevel@tonic-gate 		 * Advance past the ppp header.  Here we assume that the whole
1532*7c478bd9Sstevel@tonic-gate 		 * PPP header is in the first mblk.  (This should be true
1533*7c478bd9Sstevel@tonic-gate 		 * because the above code does pull-ups as necessary on raw
1534*7c478bd9Sstevel@tonic-gate 		 * data, and the decompressor engines all produce large blocks
1535*7c478bd9Sstevel@tonic-gate 		 * on output.)
1536*7c478bd9Sstevel@tonic-gate 		 */
1537*7c478bd9Sstevel@tonic-gate 		np = mp;
1538*7c478bd9Sstevel@tonic-gate 		dp = np->b_rptr + PPP_HDRLEN;
1539*7c478bd9Sstevel@tonic-gate 		if (dp >= mp->b_wptr) {
1540*7c478bd9Sstevel@tonic-gate 			np = np->b_cont;
1541*7c478bd9Sstevel@tonic-gate 			dp = np->b_rptr;
1542*7c478bd9Sstevel@tonic-gate 		}
1543*7c478bd9Sstevel@tonic-gate 		/*
1544*7c478bd9Sstevel@tonic-gate 		 * Make sure we have sufficient contiguous data at this point,
1545*7c478bd9Sstevel@tonic-gate 		 * which in most cases we will always do.
1546*7c478bd9Sstevel@tonic-gate 		 */
1547*7c478bd9Sstevel@tonic-gate 		hlen = (proto == PPP_VJC_COMP) ? MAX_VJHDR : MAX_TCPIPHLEN;
1548*7c478bd9Sstevel@tonic-gate 		if (hlen > len) {
1549*7c478bd9Sstevel@tonic-gate 			hlen = len;
1550*7c478bd9Sstevel@tonic-gate 		}
1551*7c478bd9Sstevel@tonic-gate 		if ((np->b_wptr < dp + hlen) || DB_REF(np) > 1) {
1552*7c478bd9Sstevel@tonic-gate #ifdef SPC_DEBUG
1553*7c478bd9Sstevel@tonic-gate 			mutex_enter(&cp->cp_pair_lock);
1554*7c478bd9Sstevel@tonic-gate 			cp->cp_imsg_vj_pull++;
1555*7c478bd9Sstevel@tonic-gate 			mutex_exit(&cp->cp_pair_lock);
1556*7c478bd9Sstevel@tonic-gate #endif
1557*7c478bd9Sstevel@tonic-gate 			zmp = msgpullup(mp, hlen + PPP_HDRLEN);
1558*7c478bd9Sstevel@tonic-gate 			freemsg(mp);
1559*7c478bd9Sstevel@tonic-gate 			mp = zmp;
1560*7c478bd9Sstevel@tonic-gate 			if (mp == NULL) {
1561*7c478bd9Sstevel@tonic-gate 				goto bad;
1562*7c478bd9Sstevel@tonic-gate 			}
1563*7c478bd9Sstevel@tonic-gate 			np = mp;
1564*7c478bd9Sstevel@tonic-gate 			dp = np->b_rptr + PPP_HDRLEN;
1565*7c478bd9Sstevel@tonic-gate 		}
1566*7c478bd9Sstevel@tonic-gate 
1567*7c478bd9Sstevel@tonic-gate 		if (proto == PPP_VJC_COMP) {
1568*7c478bd9Sstevel@tonic-gate 			uchar_t		*iphdr;
1569*7c478bd9Sstevel@tonic-gate 			int		vjlen;
1570*7c478bd9Sstevel@tonic-gate 			uint_t		iphlen;
1571*7c478bd9Sstevel@tonic-gate 			int		errcnt;
1572*7c478bd9Sstevel@tonic-gate 
1573*7c478bd9Sstevel@tonic-gate 			/*
1574*7c478bd9Sstevel@tonic-gate 			 * Decompress VJ-compressed packet.  First
1575*7c478bd9Sstevel@tonic-gate 			 * reset compressor if an input error has
1576*7c478bd9Sstevel@tonic-gate 			 * occurred.  (No need to lock statistics
1577*7c478bd9Sstevel@tonic-gate 			 * structure for read of a single word.)
1578*7c478bd9Sstevel@tonic-gate 			 */
1579*7c478bd9Sstevel@tonic-gate 			errcnt = cp->cp_stats.ppp_ierrors;
1580*7c478bd9Sstevel@tonic-gate 			if (errcnt != cp->cp_vj_last_ierrors) {
1581*7c478bd9Sstevel@tonic-gate 				cp->cp_vj_last_ierrors = errcnt;
1582*7c478bd9Sstevel@tonic-gate 				vj_uncompress_err(&cp->cp_vj);
1583*7c478bd9Sstevel@tonic-gate 			}
1584*7c478bd9Sstevel@tonic-gate 
1585*7c478bd9Sstevel@tonic-gate 			vjlen = vj_uncompress_tcp(dp, np->b_wptr - dp, len,
1586*7c478bd9Sstevel@tonic-gate 					&cp->cp_vj, &iphdr, &iphlen);
1587*7c478bd9Sstevel@tonic-gate 
1588*7c478bd9Sstevel@tonic-gate 			if (vjlen < 0 || iphlen == 0) {
1589*7c478bd9Sstevel@tonic-gate 				/*
1590*7c478bd9Sstevel@tonic-gate 				 * so we don't reset next time
1591*7c478bd9Sstevel@tonic-gate 				 */
1592*7c478bd9Sstevel@tonic-gate 				mutex_enter(&cp->cp_pair_lock);
1593*7c478bd9Sstevel@tonic-gate 				++cp->cp_vj_last_ierrors;
1594*7c478bd9Sstevel@tonic-gate 				mutex_exit(&cp->cp_pair_lock);
1595*7c478bd9Sstevel@tonic-gate 				goto bad;
1596*7c478bd9Sstevel@tonic-gate 			}
1597*7c478bd9Sstevel@tonic-gate 			/*
1598*7c478bd9Sstevel@tonic-gate 			 * drop ppp and vj headers off
1599*7c478bd9Sstevel@tonic-gate 			 */
1600*7c478bd9Sstevel@tonic-gate 			if (mp != np) {
1601*7c478bd9Sstevel@tonic-gate 				freeb(mp);
1602*7c478bd9Sstevel@tonic-gate 				mp = np;
1603*7c478bd9Sstevel@tonic-gate 			}
1604*7c478bd9Sstevel@tonic-gate 			mp->b_rptr = dp + vjlen;
1605*7c478bd9Sstevel@tonic-gate 			/*
1606*7c478bd9Sstevel@tonic-gate 			 * allocate a new mblk for the ppp and
1607*7c478bd9Sstevel@tonic-gate 			 * ip headers
1608*7c478bd9Sstevel@tonic-gate 			 */
1609*7c478bd9Sstevel@tonic-gate 			np = allocb(iphlen + PPP_HDRLEN, BPRI_MED);
1610*7c478bd9Sstevel@tonic-gate 			if (np == NULL)
1611*7c478bd9Sstevel@tonic-gate 				goto bad;
1612*7c478bd9Sstevel@tonic-gate 			dp = np->b_rptr;
1613*7c478bd9Sstevel@tonic-gate 			/*
1614*7c478bd9Sstevel@tonic-gate 			 * reconstruct PPP header
1615*7c478bd9Sstevel@tonic-gate 			 */
1616*7c478bd9Sstevel@tonic-gate 			dp[0] = PPP_ALLSTATIONS;
1617*7c478bd9Sstevel@tonic-gate 			dp[1] = PPP_UI;
1618*7c478bd9Sstevel@tonic-gate 			dp[2] = PPP_IP >> 8;
1619*7c478bd9Sstevel@tonic-gate 			dp[3] = PPP_IP;
1620*7c478bd9Sstevel@tonic-gate 			/*
1621*7c478bd9Sstevel@tonic-gate 			 * prepend mblk with reconstructed TCP/IP header.
1622*7c478bd9Sstevel@tonic-gate 			 */
1623*7c478bd9Sstevel@tonic-gate 			bcopy((caddr_t)iphdr, (caddr_t)dp + PPP_HDRLEN, iphlen);
1624*7c478bd9Sstevel@tonic-gate 			np->b_wptr = dp + iphlen + PPP_HDRLEN;
1625*7c478bd9Sstevel@tonic-gate 			np->b_cont = mp;
1626*7c478bd9Sstevel@tonic-gate 			mp = np;
1627*7c478bd9Sstevel@tonic-gate 		} else {
1628*7c478bd9Sstevel@tonic-gate 			/*
1629*7c478bd9Sstevel@tonic-gate 			 * "Decompress" a VJ-uncompressed packet.
1630*7c478bd9Sstevel@tonic-gate 			 */
1631*7c478bd9Sstevel@tonic-gate 			mutex_enter(&cp->cp_pair_lock);
1632*7c478bd9Sstevel@tonic-gate 			cp->cp_vj_last_ierrors = cp->cp_stats.ppp_ierrors;
1633*7c478bd9Sstevel@tonic-gate 			mutex_exit(&cp->cp_pair_lock);
1634*7c478bd9Sstevel@tonic-gate 			if (!vj_uncompress_uncomp(dp, hlen, &cp->cp_vj)) {
1635*7c478bd9Sstevel@tonic-gate 				/*
1636*7c478bd9Sstevel@tonic-gate 				 * don't need to reset next time
1637*7c478bd9Sstevel@tonic-gate 				 */
1638*7c478bd9Sstevel@tonic-gate 				mutex_enter(&cp->cp_pair_lock);
1639*7c478bd9Sstevel@tonic-gate 				++cp->cp_vj_last_ierrors;
1640*7c478bd9Sstevel@tonic-gate 				mutex_exit(&cp->cp_pair_lock);
1641*7c478bd9Sstevel@tonic-gate 				goto bad;
1642*7c478bd9Sstevel@tonic-gate 			}
1643*7c478bd9Sstevel@tonic-gate 			/*
1644*7c478bd9Sstevel@tonic-gate 			 * fix up the PPP protocol field
1645*7c478bd9Sstevel@tonic-gate 			 */
1646*7c478bd9Sstevel@tonic-gate 			mp->b_rptr[3] = PPP_IP;
1647*7c478bd9Sstevel@tonic-gate 		}
1648*7c478bd9Sstevel@tonic-gate 	}
1649*7c478bd9Sstevel@tonic-gate 	CPDEBUG((DBGSTART "recv (%ld bytes) flags=0x%b\n",
1650*7c478bd9Sstevel@tonic-gate 	    (IS_CP_HASUNIT(cp) ? cp->cp_unit : -1), msgsize(mp),
1651*7c478bd9Sstevel@tonic-gate 	    cp->cp_flags, CP_FLAGSSTR));
1652*7c478bd9Sstevel@tonic-gate 	return (mp);
1653*7c478bd9Sstevel@tonic-gate 
1654*7c478bd9Sstevel@tonic-gate bad:
1655*7c478bd9Sstevel@tonic-gate 	if (mp != 0) {
1656*7c478bd9Sstevel@tonic-gate 		freemsg(mp);
1657*7c478bd9Sstevel@tonic-gate 	}
1658*7c478bd9Sstevel@tonic-gate 	mutex_enter(&cp->cp_pair_lock);
1659*7c478bd9Sstevel@tonic-gate 	cp->cp_stats.ppp_ierrors++;
1660*7c478bd9Sstevel@tonic-gate 	mutex_exit(&cp->cp_pair_lock);
1661*7c478bd9Sstevel@tonic-gate 	(void) putnextctl1(q, M_CTL, PPPCTL_IERROR);
1662*7c478bd9Sstevel@tonic-gate 	return (NULL);
1663*7c478bd9Sstevel@tonic-gate }
1664*7c478bd9Sstevel@tonic-gate 
1665*7c478bd9Sstevel@tonic-gate /*
1666*7c478bd9Sstevel@tonic-gate  * comp_ccp()
1667*7c478bd9Sstevel@tonic-gate  *
1668*7c478bd9Sstevel@tonic-gate  * Description:
1669*7c478bd9Sstevel@tonic-gate  *    Called by spppcomp_outpkt and spppcomp_inpkt to handle a CCP
1670*7c478bd9Sstevel@tonic-gate  *    negotiation packet being sent or received.  Here all the data in
1671*7c478bd9Sstevel@tonic-gate  *    the packet is in a single mbuf.
1672*7c478bd9Sstevel@tonic-gate  *
1673*7c478bd9Sstevel@tonic-gate  *	Global state is updated.  Must be called with mutex held.
1674*7c478bd9Sstevel@tonic-gate  */
1675*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
1676*7c478bd9Sstevel@tonic-gate static void
1677*7c478bd9Sstevel@tonic-gate comp_ccp(queue_t *q, mblk_t *mp, sppp_comp_t *cp, boolean_t rcvd)
1678*7c478bd9Sstevel@tonic-gate {
1679*7c478bd9Sstevel@tonic-gate 	int	len;
1680*7c478bd9Sstevel@tonic-gate 	int	clen;
1681*7c478bd9Sstevel@tonic-gate 	uchar_t	*dp;
1682*7c478bd9Sstevel@tonic-gate 
1683*7c478bd9Sstevel@tonic-gate 	ASSERT(q != NULL);
1684*7c478bd9Sstevel@tonic-gate 	ASSERT(q->q_ptr != NULL);
1685*7c478bd9Sstevel@tonic-gate 	ASSERT(mp != NULL);
1686*7c478bd9Sstevel@tonic-gate 	ASSERT(cp != NULL);
1687*7c478bd9Sstevel@tonic-gate 
1688*7c478bd9Sstevel@tonic-gate 	len = msgsize(mp);
1689*7c478bd9Sstevel@tonic-gate 	if (len < PPP_HDRLEN + CCP_HDRLEN) {
1690*7c478bd9Sstevel@tonic-gate 		return;
1691*7c478bd9Sstevel@tonic-gate 	}
1692*7c478bd9Sstevel@tonic-gate 	dp = mp->b_rptr + PPP_HDRLEN;
1693*7c478bd9Sstevel@tonic-gate 
1694*7c478bd9Sstevel@tonic-gate 	len -= PPP_HDRLEN;
1695*7c478bd9Sstevel@tonic-gate 	clen = CCP_LENGTH(dp);
1696*7c478bd9Sstevel@tonic-gate 	if (clen > len) {
1697*7c478bd9Sstevel@tonic-gate 		return;
1698*7c478bd9Sstevel@tonic-gate 	}
1699*7c478bd9Sstevel@tonic-gate 
1700*7c478bd9Sstevel@tonic-gate 	CPDEBUG((DBGSTART "CCP code=%d flags=0x%b\n",
1701*7c478bd9Sstevel@tonic-gate 	    (IS_CP_HASUNIT(cp) ? cp->cp_unit : -1), CCP_CODE(dp),
1702*7c478bd9Sstevel@tonic-gate 	    cp->cp_flags, CP_FLAGSSTR));
1703*7c478bd9Sstevel@tonic-gate 	switch (CCP_CODE(dp)) {
1704*7c478bd9Sstevel@tonic-gate 	case CCP_CONFREQ:
1705*7c478bd9Sstevel@tonic-gate 	case CCP_TERMREQ:
1706*7c478bd9Sstevel@tonic-gate 	case CCP_TERMACK:
1707*7c478bd9Sstevel@tonic-gate 		cp->cp_flags &= ~CCP_ISUP;
1708*7c478bd9Sstevel@tonic-gate 		break;
1709*7c478bd9Sstevel@tonic-gate 	case CCP_CONFACK:
1710*7c478bd9Sstevel@tonic-gate 		if ((cp->cp_flags & (CCP_ISOPEN | CCP_ISUP)) == CCP_ISOPEN &&
1711*7c478bd9Sstevel@tonic-gate 			clen >= CCP_HDRLEN + CCP_OPT_MINLEN &&
1712*7c478bd9Sstevel@tonic-gate 			clen >= CCP_HDRLEN + CCP_OPT_LENGTH(dp + CCP_HDRLEN)) {
1713*7c478bd9Sstevel@tonic-gate 
1714*7c478bd9Sstevel@tonic-gate 			int	rc;
1715*7c478bd9Sstevel@tonic-gate 
1716*7c478bd9Sstevel@tonic-gate 			if (!rcvd) {
1717*7c478bd9Sstevel@tonic-gate 				rc = (*cp->cp_xcomp->comp_init)(cp->cp_xstate,
1718*7c478bd9Sstevel@tonic-gate 				    dp + CCP_HDRLEN, clen - CCP_HDRLEN,
1719*7c478bd9Sstevel@tonic-gate 				    cp->cp_unit, 0,
1720*7c478bd9Sstevel@tonic-gate 				    IS_CP_KDEBUG(cp) | ALG_DEBUG);
1721*7c478bd9Sstevel@tonic-gate 
1722*7c478bd9Sstevel@tonic-gate 				if (cp->cp_xstate != NULL && rc != 0) {
1723*7c478bd9Sstevel@tonic-gate 					cp->cp_flags |= CCP_COMP_RUN;
1724*7c478bd9Sstevel@tonic-gate 				}
1725*7c478bd9Sstevel@tonic-gate 			} else {
1726*7c478bd9Sstevel@tonic-gate 				rc = (*cp->cp_rcomp->decomp_init)(cp->
1727*7c478bd9Sstevel@tonic-gate 				    cp_rstate, dp + CCP_HDRLEN,
1728*7c478bd9Sstevel@tonic-gate 				    clen - CCP_HDRLEN, cp->cp_unit, 0,
1729*7c478bd9Sstevel@tonic-gate 				    cp->cp_mru,
1730*7c478bd9Sstevel@tonic-gate 				    IS_CP_KDEBUG(cp) | ALG_DEBUG);
1731*7c478bd9Sstevel@tonic-gate 
1732*7c478bd9Sstevel@tonic-gate 				if (cp->cp_rstate != NULL && rc != 0) {
1733*7c478bd9Sstevel@tonic-gate 					cp->cp_flags &= ~CCP_ERR;
1734*7c478bd9Sstevel@tonic-gate 					cp->cp_flags |= CCP_DECOMP_RUN;
1735*7c478bd9Sstevel@tonic-gate 				}
1736*7c478bd9Sstevel@tonic-gate 			}
1737*7c478bd9Sstevel@tonic-gate 		}
1738*7c478bd9Sstevel@tonic-gate 		break;
1739*7c478bd9Sstevel@tonic-gate 	case CCP_RESETACK:
1740*7c478bd9Sstevel@tonic-gate 		if (IS_CCP_ISUP(cp)) {
1741*7c478bd9Sstevel@tonic-gate 			if (!rcvd) {
1742*7c478bd9Sstevel@tonic-gate 				if (cp->cp_xstate != NULL &&
1743*7c478bd9Sstevel@tonic-gate 				    IS_CCP_COMP_RUN(cp)) {
1744*7c478bd9Sstevel@tonic-gate 					(*cp->cp_xcomp->comp_reset)(cp->
1745*7c478bd9Sstevel@tonic-gate 					    cp_xstate);
1746*7c478bd9Sstevel@tonic-gate 				}
1747*7c478bd9Sstevel@tonic-gate 			} else {
1748*7c478bd9Sstevel@tonic-gate 				if (cp->cp_rstate != NULL &&
1749*7c478bd9Sstevel@tonic-gate 				    IS_CCP_DECOMP_RUN(cp)) {
1750*7c478bd9Sstevel@tonic-gate 					(*cp->cp_rcomp->decomp_reset)(cp->
1751*7c478bd9Sstevel@tonic-gate 					    cp_rstate);
1752*7c478bd9Sstevel@tonic-gate 					cp->cp_flags &= ~CCP_ERROR;
1753*7c478bd9Sstevel@tonic-gate 				}
1754*7c478bd9Sstevel@tonic-gate 			}
1755*7c478bd9Sstevel@tonic-gate 		}
1756*7c478bd9Sstevel@tonic-gate 		break;
1757*7c478bd9Sstevel@tonic-gate 	}
1758*7c478bd9Sstevel@tonic-gate }
1759*7c478bd9Sstevel@tonic-gate 
1760*7c478bd9Sstevel@tonic-gate /*
1761*7c478bd9Sstevel@tonic-gate  * spppcomp_kstat_update()
1762*7c478bd9Sstevel@tonic-gate  *
1763*7c478bd9Sstevel@tonic-gate  * Description:
1764*7c478bd9Sstevel@tonic-gate  *    Update per-unit kstat statistics.
1765*7c478bd9Sstevel@tonic-gate  */
1766*7c478bd9Sstevel@tonic-gate static int
1767*7c478bd9Sstevel@tonic-gate spppcomp_kstat_update(kstat_t *ksp, int rw)
1768*7c478bd9Sstevel@tonic-gate {
1769*7c478bd9Sstevel@tonic-gate 	register sppp_comp_t		*cp;
1770*7c478bd9Sstevel@tonic-gate 	register spppcomp_kstats_t	*cpkp;
1771*7c478bd9Sstevel@tonic-gate 	register struct vjstat		*sp;
1772*7c478bd9Sstevel@tonic-gate 	register struct pppstat64	*psp;
1773*7c478bd9Sstevel@tonic-gate 	struct ppp_comp_stats		csp;
1774*7c478bd9Sstevel@tonic-gate 
1775*7c478bd9Sstevel@tonic-gate 	if (rw == KSTAT_WRITE) {
1776*7c478bd9Sstevel@tonic-gate 		return (EACCES);
1777*7c478bd9Sstevel@tonic-gate 	}
1778*7c478bd9Sstevel@tonic-gate 
1779*7c478bd9Sstevel@tonic-gate 	cp = (sppp_comp_t *)ksp->ks_private;
1780*7c478bd9Sstevel@tonic-gate 	ASSERT(cp != NULL);
1781*7c478bd9Sstevel@tonic-gate 
1782*7c478bd9Sstevel@tonic-gate 	cpkp = (spppcomp_kstats_t *)ksp->ks_data;
1783*7c478bd9Sstevel@tonic-gate 	bzero((caddr_t)&csp, sizeof (struct ppp_comp_stats));
1784*7c478bd9Sstevel@tonic-gate 
1785*7c478bd9Sstevel@tonic-gate 	mutex_enter(&cp->cp_pair_lock);
1786*7c478bd9Sstevel@tonic-gate 
1787*7c478bd9Sstevel@tonic-gate 	if (cp->cp_xstate != NULL) {
1788*7c478bd9Sstevel@tonic-gate 		(*cp->cp_xcomp->comp_stat)(cp->cp_xstate, &csp.c);
1789*7c478bd9Sstevel@tonic-gate 	}
1790*7c478bd9Sstevel@tonic-gate 	if (cp->cp_rstate != NULL) {
1791*7c478bd9Sstevel@tonic-gate 		(*cp->cp_rcomp->decomp_stat)(cp->cp_rstate, &csp.d);
1792*7c478bd9Sstevel@tonic-gate 	}
1793*7c478bd9Sstevel@tonic-gate 
1794*7c478bd9Sstevel@tonic-gate 	sp = &cp->cp_vj.stats;
1795*7c478bd9Sstevel@tonic-gate 
1796*7c478bd9Sstevel@tonic-gate 	cpkp->vj_out_pkts.value.ui32		= sp->vjs_packets;
1797*7c478bd9Sstevel@tonic-gate 	cpkp->vj_out_pkts_comp.value.ui32	= sp->vjs_compressed;
1798*7c478bd9Sstevel@tonic-gate 	cpkp->vj_cs_searches.value.ui32		= sp->vjs_searches;
1799*7c478bd9Sstevel@tonic-gate 	cpkp->vj_cs_misses.value.ui32		= sp->vjs_misses;
1800*7c478bd9Sstevel@tonic-gate 	cpkp->vj_in_pkts_uncomp.value.ui32	= sp->vjs_uncompressedin;
1801*7c478bd9Sstevel@tonic-gate 	cpkp->vj_in_pkts_comp.value.ui32	= sp->vjs_compressedin;
1802*7c478bd9Sstevel@tonic-gate 	cpkp->vj_in_error.value.ui32		= sp->vjs_errorin;
1803*7c478bd9Sstevel@tonic-gate 	cpkp->vj_in_tossed.value.ui32		= sp->vjs_tossed;
1804*7c478bd9Sstevel@tonic-gate 
1805*7c478bd9Sstevel@tonic-gate 	psp = &cp->cp_stats;
1806*7c478bd9Sstevel@tonic-gate 
1807*7c478bd9Sstevel@tonic-gate 	cpkp->out_bytes.value.ui64		= psp->ppp_obytes;
1808*7c478bd9Sstevel@tonic-gate 	cpkp->out_pkts.value.ui64		= psp->ppp_opackets;
1809*7c478bd9Sstevel@tonic-gate 	cpkp->out_errors.value.ui64		= psp->ppp_oerrors;
1810*7c478bd9Sstevel@tonic-gate 	cpkp->out_errors_low.value.ui32		= cp->cp_oerr_low;
1811*7c478bd9Sstevel@tonic-gate 	cpkp->out_uncomp_bytes.value.ui32	= csp.c.unc_bytes;
1812*7c478bd9Sstevel@tonic-gate 	cpkp->out_uncomp_pkts.value.ui32	= csp.c.unc_packets;
1813*7c478bd9Sstevel@tonic-gate 	cpkp->out_comp_bytes.value.ui32		= csp.c.comp_bytes;
1814*7c478bd9Sstevel@tonic-gate 	cpkp->out_comp_pkts.value.ui32		= csp.c.comp_packets;
1815*7c478bd9Sstevel@tonic-gate 	cpkp->out_incomp_bytes.value.ui32	= csp.c.inc_bytes;
1816*7c478bd9Sstevel@tonic-gate 	cpkp->out_incomp_pkts.value.ui32	= csp.c.inc_packets;
1817*7c478bd9Sstevel@tonic-gate 
1818*7c478bd9Sstevel@tonic-gate 	cpkp->in_bytes.value.ui64		= psp->ppp_ibytes;
1819*7c478bd9Sstevel@tonic-gate 	cpkp->in_pkts.value.ui64		= psp->ppp_ipackets;
1820*7c478bd9Sstevel@tonic-gate 	cpkp->in_errors.value.ui64		= psp->ppp_ierrors;
1821*7c478bd9Sstevel@tonic-gate 	cpkp->in_errors_low.value.ui32		= cp->cp_ierr_low;
1822*7c478bd9Sstevel@tonic-gate 	cpkp->in_uncomp_bytes.value.ui32	= csp.d.unc_bytes;
1823*7c478bd9Sstevel@tonic-gate 	cpkp->in_uncomp_pkts.value.ui32		= csp.d.unc_packets;
1824*7c478bd9Sstevel@tonic-gate 	cpkp->in_comp_bytes.value.ui32		= csp.d.comp_bytes;
1825*7c478bd9Sstevel@tonic-gate 	cpkp->in_comp_pkts.value.ui32		= csp.d.comp_packets;
1826*7c478bd9Sstevel@tonic-gate 	cpkp->in_incomp_bytes.value.ui32	= csp.d.inc_bytes;
1827*7c478bd9Sstevel@tonic-gate 	cpkp->in_incomp_pkts.value.ui32		= csp.d.inc_packets;
1828*7c478bd9Sstevel@tonic-gate #ifdef SPC_DEBUG
1829*7c478bd9Sstevel@tonic-gate 	cpkp->in_msg_ccp_pulledup.value.ui32	= cp->cp_imsg_ccp_pull;
1830*7c478bd9Sstevel@tonic-gate 	cpkp->in_msg_vj_pulledup.value.ui32	= cp->cp_imsg_vj_pull;
1831*7c478bd9Sstevel@tonic-gate 	cpkp->out_msg_pulledup.value.ui32	= cp->cp_omsg_pull;
1832*7c478bd9Sstevel@tonic-gate 	cpkp->out_msg_copied.value.ui32		= cp->cp_omsg_dcopy;
1833*7c478bd9Sstevel@tonic-gate 	cpkp->out_queued.value.ui32		= cp->cp_out_queued;
1834*7c478bd9Sstevel@tonic-gate 	cpkp->out_handled.value.ui32		= cp->cp_out_handled;
1835*7c478bd9Sstevel@tonic-gate 	cpkp->in_queued.value.ui32		= cp->cp_in_queued;
1836*7c478bd9Sstevel@tonic-gate 	cpkp->in_handled.value.ui32		= cp->cp_in_handled;
1837*7c478bd9Sstevel@tonic-gate #endif
1838*7c478bd9Sstevel@tonic-gate 	mutex_exit(&cp->cp_pair_lock);
1839*7c478bd9Sstevel@tonic-gate 	return (0);
1840*7c478bd9Sstevel@tonic-gate }
1841