xref: /titanic_52/usr/src/uts/common/io/ppp/spppasyn/spppasyn.c (revision cd3e933325e68e23516a196a8fea7f49b1e497c3)
1 /*
2  * spppasyn.c - STREAMS module for doing PPP asynchronous HDLC.
3  *
4  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
5  * Use is subject to license terms.
6  *
7  * Permission to use, copy, modify, and distribute this software and its
8  * documentation is hereby granted, provided that the above copyright
9  * notice appears in all copies.
10  *
11  * SUN MAKES NO REPRESENTATION OR WARRANTIES ABOUT THE SUITABILITY OF
12  * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
13  * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
14  * PARTICULAR PURPOSE, OR NON-INFRINGEMENT.  SUN SHALL NOT BE LIABLE FOR
15  * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
16  * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES
17  *
18  * Copyright (c) 1994 The Australian National University.
19  * All rights reserved.
20  *
21  * Permission to use, copy, modify, and distribute this software and its
22  * documentation is hereby granted, provided that the above copyright
23  * notice appears in all copies.  This software is provided without any
24  * warranty, express or implied. The Australian National University
25  * makes no representations about the suitability of this software for
26  * any purpose.
27  *
28  * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
29  * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
30  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
31  * THE AUSTRALIAN NATIONAL UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY
32  * OF SUCH DAMAGE.
33  *
34  * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
35  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
36  * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
37  * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
38  * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
39  * OR MODIFICATIONS.
40  *
41  * $Id: ppp_ahdlc.c,v 1.16 2000/03/06 19:38:12 masputra Exp $
42  */
43 
44 #pragma ident	"%Z%%M%	%I%	%E% SMI"
45 
46 #include <sys/types.h>
47 #include <sys/param.h>
48 #include <sys/stream.h>
49 #include <sys/strsun.h>
50 #include <sys/sysmacros.h>
51 #include <sys/errno.h>
52 #include <sys/conf.h>
53 #include <sys/kmem.h>
54 #include <sys/crc32.h>
55 #include <sys/cmn_err.h>
56 #include <sys/ddi.h>
57 
58 #include <net/ppp_defs.h>
59 #include <net/pppio.h>
60 
61 #include "s_common.h"
62 
63 #ifdef DEBUG
64 #define	REPORT_CRC_TYPE
65 #endif
66 #include "spppasyn.h"
67 
68 /*
69  * This is used to tag official Solaris sources.  Please do not define
70  * "INTERNAL_BUILD" when building this software outside of Sun
71  * Microsystems.
72  */
73 #ifdef INTERNAL_BUILD
74 /* MODINFO is limited to 32 characters. */
75 const char spppasyn_module_description[] = "PPP 4.0 AHDLC";
76 #else /* INTERNAL_BUILD */
77 const char spppasyn_module_description[] = "ANU PPP AHDLC $Revision: 1.16$";
78 
79 /* LINTED */
80 static const char buildtime[] = "Built " __DATE__ " at " __TIME__
81 #ifdef DEBUG
82 " DEBUG"
83 #endif
84 "\n";
85 #endif /* INTERNAL_BUILD */
86 
87 static int	spppasyn_open(queue_t *, dev_t *, int, int, cred_t *);
88 static int	spppasyn_close(queue_t *, int, cred_t *);
89 static int	spppasyn_wput(queue_t *, mblk_t *);
90 static int	spppasyn_rput(queue_t *, mblk_t *);
91 static mblk_t	*ahdlc_encode(queue_t *, mblk_t *);
92 static mblk_t	*ahdlc_decode(queue_t *, mblk_t *);
93 static void	spppasyn_timer(void *);
94 static mblk_t	*spppasyn_inpkt(queue_t *, mblk_t *);
95 static mblk_t	*spppasyn_muxencode(queue_t *, mblk_t *);
96 
97 #define	RESET_MUX_VALUES(x)	{	\
98 	x->sa_mqhead = x->sa_mqtail = NULL;	\
99 	x->sa_proto = 0;			\
100 	x->sa_mqlen = 0;			\
101 }
102 #define	IS_XMUX_ENABLED(x)	\
103 	((x)->sa_flags & X_MUXMASK)
104 #define	IS_RMUX_ENABLED(x)	\
105 	((x)->sa_flags & R_MUXMASK)
106 #define	IS_COMP_AC(x)	\
107 	((x)->sa_flags & SAF_XCOMP_AC)
108 #define	IS_COMP_PROT(x)	\
109 	((x)->sa_flags & SAF_XCOMP_PROT)
110 #define	IS_DECOMP_PROT(x)	\
111 	((x)->sa_flags & SAF_RDECOMP_PROT)
112 
113 /*
114  * Don't send HDLC start flag if last transmit is within 1.5 seconds -
115  * FLAG_TIME is defined in nanoseconds.
116  */
117 #define	FLAG_TIME	1500000000ul
118 
119 /*
120  * The usual AHDLC implementation enables the default escaping for all
121  * LCP frames.  LCP_USE_DFLT() is used in this implementation to
122  * modify this rule slightly.  If the code number happens to be
123  * Echo-Request, Echo-Reply, or Discard-Request (each of which may be
124  * sent only when LCP is in Opened state), then one may also use the
125  * negotiated ACCM; the RFC is silent on this.  The theory is that
126  * pppd can construct Echo-Request messages that are guaranteed to
127  * fail if the negotiated ACCM is bad.
128  */
129 #define	LCP_USE_DFLT(mp)	((code = MSG_BYTE((mp), 4)) < 9 || code > 11)
130 
131 /*
132  * Extract bit c from map m, to determine if character c needs to be
133  * escaped.  Map 'm' is a pointer to a 256 bit map; 8 words of 32 bits
134  * each.
135  */
136 #define	IN_TX_MAP(c, m)	\
137 	((m)[(c) >> 5] & (1 << ((c) & 0x1f)))
138 
139 /*
140  * Checks the 32-bit receive ACCM to see if the byte should have been
141  * escaped by peer.
142  */
143 #define	IN_RX_MAP(c, m)		(((c) < 0x20) && ((m) & (1 << (c))))
144 
145 static struct module_info spppasyn_modinfo = {
146 	AHDLC_MOD_ID,		/* mi_idnum */
147 	AHDLC_MOD_NAME,		/* mi_idname */
148 	0,			/* mi_minpsz */
149 	INFPSZ,			/* mi_maxpsz */
150 	0,			/* mi_hiwat */
151 	0			/* mi_lowat */
152 };
153 
154 static struct qinit spppasyn_rinit = {
155 	spppasyn_rput,		/* qi_putp */
156 	NULL,			/* qi_srvp */
157 	spppasyn_open,		/* qi_qopen */
158 	spppasyn_close,		/* qi_qclose */
159 	NULL,			/* qi_qadmin */
160 	&spppasyn_modinfo,	/* qi_minfo */
161 	NULL			/* qi_mstat */
162 };
163 
164 static struct qinit spppasyn_winit = {
165 	spppasyn_wput,		/* qi_putp */
166 	NULL,			/* qi_srvp */
167 	NULL,			/* qi_qopen */
168 	NULL,			/* qi_qclose */
169 	NULL,			/* qi_qadmin */
170 	&spppasyn_modinfo,	/* qi_minfo */
171 	NULL			/* qi_mstat */
172 };
173 
174 struct streamtab spppasyn_tab = {
175 	&spppasyn_rinit,	/* st_rdinit */
176 	&spppasyn_winit,	/* st_wrinit */
177 	NULL,			/* st_muxrinit */
178 	NULL,			/* st_muxwinit */
179 };
180 
181 /* Matches above structure. */
182 static const char *kstat_names[] = {
183 	"ioctls", "ioctlsfwd", "ioctlserr", "ctls",
184 	"ctlsfwd", "ctlserr", "inbadchars", "inbadcharmask",
185 	"inaborts", "inrunts", "inallocfails", "intoolongs",
186 	"outrunts", "outallocfails", "incrcerrs", "unknownwrs",
187 	"unknownrds", "hangups", "datain", "dataout",
188 	"extrabufs", "sentmux", "recvmux", "inmuxerrs",
189 #ifdef REPORT_CRC_TYPE
190 	"incrctype", "outcrctype",
191 #endif
192 };
193 
194 /* So.  This is why we have optimizing compilers. */
195 #define	KVAL(vn)	state->sa_kstats.vn.value.ui32
196 #define	KSET(vn, v)	KVAL(vn) = (v)
197 #define	KADD(vn, v)	KSET(vn, KVAL(vn) + (v))
198 #define	KOR(vn, v)	KSET(vn, KVAL(vn) | (v))
199 #define	KINCR(vn)	KADD(vn, 1)
200 
201 static void ppp_dump_frame(sppp_ahdlc_t *state, mblk_t *mptr,
202     const char *msg);
203 
204 /*
205  * RCV_B7_1, etc., defined in net/pppio.h, are stored in flags also.
206  */
207 #define	RCV_FLAGS	(RCV_B7_1 | RCV_B7_0 | RCV_ODDP | RCV_EVNP)
208 
209 /*
210  * FCS lookup table as calculated by genfcstab.
211  */
212 static ushort_t fcstab[256] = {
213 	0x0000,	0x1189,	0x2312,	0x329b,	0x4624,	0x57ad,	0x6536,	0x74bf,
214 	0x8c48,	0x9dc1,	0xaf5a,	0xbed3,	0xca6c,	0xdbe5,	0xe97e,	0xf8f7,
215 	0x1081,	0x0108,	0x3393,	0x221a,	0x56a5,	0x472c,	0x75b7,	0x643e,
216 	0x9cc9,	0x8d40,	0xbfdb,	0xae52,	0xdaed,	0xcb64,	0xf9ff,	0xe876,
217 	0x2102,	0x308b,	0x0210,	0x1399,	0x6726,	0x76af,	0x4434,	0x55bd,
218 	0xad4a,	0xbcc3,	0x8e58,	0x9fd1,	0xeb6e,	0xfae7,	0xc87c,	0xd9f5,
219 	0x3183,	0x200a,	0x1291,	0x0318,	0x77a7,	0x662e,	0x54b5,	0x453c,
220 	0xbdcb,	0xac42,	0x9ed9,	0x8f50,	0xfbef,	0xea66,	0xd8fd,	0xc974,
221 	0x4204,	0x538d,	0x6116,	0x709f,	0x0420,	0x15a9,	0x2732,	0x36bb,
222 	0xce4c,	0xdfc5,	0xed5e,	0xfcd7,	0x8868,	0x99e1,	0xab7a,	0xbaf3,
223 	0x5285,	0x430c,	0x7197,	0x601e,	0x14a1,	0x0528,	0x37b3,	0x263a,
224 	0xdecd,	0xcf44,	0xfddf,	0xec56,	0x98e9,	0x8960,	0xbbfb,	0xaa72,
225 	0x6306,	0x728f,	0x4014,	0x519d,	0x2522,	0x34ab,	0x0630,	0x17b9,
226 	0xef4e,	0xfec7,	0xcc5c,	0xddd5,	0xa96a,	0xb8e3,	0x8a78,	0x9bf1,
227 	0x7387,	0x620e,	0x5095,	0x411c,	0x35a3,	0x242a,	0x16b1,	0x0738,
228 	0xffcf,	0xee46,	0xdcdd,	0xcd54,	0xb9eb,	0xa862,	0x9af9,	0x8b70,
229 	0x8408,	0x9581,	0xa71a,	0xb693,	0xc22c,	0xd3a5,	0xe13e,	0xf0b7,
230 	0x0840,	0x19c9,	0x2b52,	0x3adb,	0x4e64,	0x5fed,	0x6d76,	0x7cff,
231 	0x9489,	0x8500,	0xb79b,	0xa612,	0xd2ad,	0xc324,	0xf1bf,	0xe036,
232 	0x18c1,	0x0948,	0x3bd3,	0x2a5a,	0x5ee5,	0x4f6c,	0x7df7,	0x6c7e,
233 	0xa50a,	0xb483,	0x8618,	0x9791,	0xe32e,	0xf2a7,	0xc03c,	0xd1b5,
234 	0x2942,	0x38cb,	0x0a50,	0x1bd9,	0x6f66,	0x7eef,	0x4c74,	0x5dfd,
235 	0xb58b,	0xa402,	0x9699,	0x8710,	0xf3af,	0xe226,	0xd0bd,	0xc134,
236 	0x39c3,	0x284a,	0x1ad1,	0x0b58,	0x7fe7,	0x6e6e,	0x5cf5,	0x4d7c,
237 	0xc60c,	0xd785,	0xe51e,	0xf497,	0x8028,	0x91a1,	0xa33a,	0xb2b3,
238 	0x4a44,	0x5bcd,	0x6956,	0x78df,	0x0c60,	0x1de9,	0x2f72,	0x3efb,
239 	0xd68d,	0xc704,	0xf59f,	0xe416,	0x90a9,	0x8120,	0xb3bb,	0xa232,
240 	0x5ac5,	0x4b4c,	0x79d7,	0x685e,	0x1ce1,	0x0d68,	0x3ff3,	0x2e7a,
241 	0xe70e,	0xf687,	0xc41c,	0xd595,	0xa12a,	0xb0a3,	0x8238,	0x93b1,
242 	0x6b46,	0x7acf,	0x4854,	0x59dd,	0x2d62,	0x3ceb,	0x0e70,	0x1ff9,
243 	0xf78f,	0xe606,	0xd49d,	0xc514,	0xb1ab,	0xa022,	0x92b9,	0x8330,
244 	0x7bc7,	0x6a4e,	0x58d5,	0x495c,	0x3de3,	0x2c6a,	0x1ef1,	0x0f78
245 };
246 
247 /*
248  * Per-character flags for accumulating input errors.  Flags are
249  * accumulated for bit 7 set to 0, bit 7 set to 1, even parity
250  * characters, and odd parity characters.  The link should see all
251  * four in the very first LCP Configure-Request if all is ok.  (C0 is
252  * even parity and has bit 7 set to 1, and 23 is odd parity and has
253  * bit 7 set to 0.)
254  */
255 static uchar_t charflags[256] = {
256 	RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_ODDP,
257 	RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP,
258 	RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_ODDP,
259 	RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP,
260 	RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_ODDP,
261 	RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP,
262 	RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP,
263 	RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP,
264 	RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_ODDP,
265 	RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP,
266 	RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_ODDP,
267 	RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP,
268 	RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_ODDP,
269 	RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP,
270 	RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP,
271 	RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP,
272 	RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_ODDP,
273 	RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP,
274 	RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_ODDP,
275 	RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP,
276 	RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_ODDP,
277 	RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP,
278 	RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP,
279 	RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP,
280 	RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_ODDP,
281 	RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP,
282 	RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP,
283 	RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP,
284 	RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_EVNP,
285 	RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP,
286 	RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP,
287 	RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP,
288 	RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_ODDP,
289 	RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP,
290 	RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_ODDP,
291 	RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP,
292 	RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_ODDP,
293 	RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP,
294 	RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP,
295 	RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP,
296 	RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_ODDP,
297 	RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP,
298 	RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_1|RCV_ODDP,
299 	RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP,
300 	RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_ODDP,
301 	RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP,
302 	RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP,
303 	RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP,
304 	RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_ODDP,
305 	RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_EVNP,
306 	RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_ODDP,
307 	RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP,
308 	RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_ODDP,
309 	RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP,
310 	RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP,
311 	RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP,
312 	RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_EVNP,
313 	RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP,
314 	RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP,
315 	RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP,
316 	RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_ODDP,
317 	RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP,
318 	RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP,
319 	RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP,
320 	RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_ODDP,
321 	RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_EVNP,
322 	RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_ODDP,
323 	RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP,
324 	RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_ODDP,
325 	RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_EVNP,
326 	RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_EVNP,
327 	RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_EVNP,
328 	RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_ODDP,
329 	RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_EVNP,
330 	RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_ODDP,
331 	RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP,
332 	RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_ODDP,
333 	RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP,
334 	RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP,
335 	RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP,
336 	RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_ODDP,
337 	RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_EVNP,
338 	RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_ODDP,
339 	RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP,
340 	RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_ODDP,
341 	RCV_B7_1|RCV_EVNP
342 };
343 
344 /*
345  * Append two lists; preserve message boundaries.
346  * Warning: uses b_next.
347  */
348 static mblk_t *
349 sppp_mappend(mblk_t *m1, mblk_t *m2)
350 {
351 	mblk_t *mret;
352 
353 	if (m1 == NULL)
354 		return (m2);
355 	if (m2 == NULL)
356 		return (m1);
357 
358 	mret = m1;
359 	while (m1->b_next != NULL)
360 		m1 = m1->b_next;
361 	m1->b_next = m2;
362 	return (mret);
363 }
364 
365 /*
366  * Concatenate two mblk lists.
367  */
368 static mblk_t *
369 sppp_mcat(mblk_t *m1, mblk_t *m2)
370 {
371 	mblk_t *mret;
372 
373 	if (m1 == NULL)
374 		return (m2);
375 	if (m2 == NULL)
376 		return (m1);
377 
378 	mret = m1;
379 	while (m1->b_cont != NULL)
380 		m1 = m1->b_cont;
381 	m1->b_cont = m2;
382 	return (mret);
383 }
384 
385 /*
386  * spppasyn_open()
387  *
388  * STREAMS module open (entry) point.  Called when spppasyn is pushed
389  * onto an asynchronous serial stream.
390  */
391 /* ARGSUSED */
392 static int
393 spppasyn_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp)
394 {
395 	sppp_ahdlc_t	*state;
396 
397 	ASSERT(q != NULL);
398 
399 	if (q->q_ptr != NULL) {
400 		return (0);		/* return if already opened */
401 	}
402 
403 	if (sflag != MODOPEN) {
404 		return (EINVAL);	/* only open as a module */
405 	}
406 
407 	state = (sppp_ahdlc_t *)kmem_zalloc(sizeof (sppp_ahdlc_t), KM_SLEEP);
408 	ASSERT(state != NULL);
409 
410 	q->q_ptr = (caddr_t)state;
411 	WR(q)->q_ptr = (caddr_t)state;
412 
413 	state->sa_xaccm[0] = 0xffffffff;	/* escape 0x00 through 0x1f */
414 	state->sa_xaccm[3] = 0x60000000;   /* escape 0x7d and 0x7e */
415 	state->sa_mru = PPP_MRU;		/* default of 1500 bytes */
416 
417 	qprocson(q);
418 
419 	return (0);
420 }
421 
422 /*
423  * spppasyn_close()
424  *
425  * STREAMS module close (exit) point
426  */
427 /* ARGSUSED */
428 static int
429 spppasyn_close(queue_t *q, int flag, cred_t *credp)
430 {
431 	sppp_ahdlc_t	*state;
432 
433 	ASSERT(q != NULL);
434 	state = (sppp_ahdlc_t *)q->q_ptr;
435 	ASSERT(state != NULL);
436 
437 	/* We're leaving now.  No more calls, please. */
438 	qprocsoff(q);
439 
440 	if (state->sa_rx_buf != NULL) {
441 		freemsg(state->sa_rx_buf);
442 		state->sa_rx_buf = NULL;
443 	}
444 
445 	if (state->sa_ksp != NULL) {
446 		kstat_delete(state->sa_ksp);
447 		state->sa_ksp = NULL;
448 	}
449 
450 	if (state->sa_mqhead != NULL)
451 		freemsg(state->sa_mqhead);
452 	/* remove the time out routine */
453 	if (state->sa_timeout_id != 0)
454 		(void) quntimeout(q, state->sa_timeout_id);
455 
456 	q->q_ptr = NULL;
457 	WR(q)->q_ptr = NULL;
458 	kmem_free(state, sizeof (sppp_ahdlc_t));
459 
460 	return (0);
461 }
462 
463 /*
464  * Create the standard kernel statistics structure and attach it to
465  * the current state structure.  This can be called only after
466  * assigning the unit number.
467  */
468 static void
469 create_kstats(sppp_ahdlc_t *state)
470 {
471 	kstat_t *ksp;
472 	char unitname[KSTAT_STRLEN];
473 	int nstat, i;
474 	kstat_named_t *knt;
475 
476 	nstat = sizeof (state->sa_kstats) / sizeof (kstat_named_t);
477 	knt = (kstat_named_t *)&state->sa_kstats;
478 	for (i = 0; i < nstat; i++, knt++) {
479 #ifdef DEBUG
480 		/* Just in case I do something silly here. */
481 		if (i >= sizeof (kstat_names) / sizeof (kstat_names[0]))
482 			(void) sprintf(knt->name, "unknown%d", i);
483 		else
484 #endif
485 			(void) strncpy(knt->name, kstat_names[i],
486 			    sizeof (knt->name));
487 		knt->data_type = KSTAT_DATA_UINT32;
488 	}
489 	/*
490 	 * sprintf is known to be safe here because KSTAT_STRLEN is
491 	 * 31, the maximum module name length is 8, and the maximum
492 	 * string length from %d is 11.  This was once snprintf, but
493 	 * that's not backward-compatible with Solaris 2.6.
494 	 */
495 	(void) sprintf(unitname, "%s" "%d", AHDLC_MOD_NAME, state->sa_unit);
496 	ksp = kstat_create(AHDLC_MOD_NAME, state->sa_unit, unitname, "net",
497 	    KSTAT_TYPE_NAMED, nstat, KSTAT_FLAG_VIRTUAL);
498 	if (ksp != NULL) {
499 		ksp->ks_data = (void *)&state->sa_kstats;
500 		kstat_install(ksp);
501 	}
502 	state->sa_ksp = ksp;
503 #ifdef REPORT_CRC_TYPE
504 	KSET(pks_outcrctype, 16);
505 	KSET(pks_incrctype, 16);
506 #endif
507 }
508 
509 /*
510  * spppasyn_inner_ioctl
511  *
512  * MT-Perimeters:
513  *	exclusive inner
514  *
515  * Handle state-affecting ioctls.
516  */
517 static void
518 spppasyn_inner_ioctl(queue_t *q, mblk_t *mp)
519 {
520 	sppp_ahdlc_t		*state;
521 	struct iocblk		*iop;
522 	int			error;
523 	int			flagval;
524 	int			len;
525 	uint32_t		mux_flags;
526 	uint32_t		mask;
527 	int			flagmask;
528 
529 	ASSERT(q != NULL && mp != NULL);
530 	state = (sppp_ahdlc_t *)q->q_ptr;
531 	iop = (struct iocblk *)mp->b_rptr;
532 	ASSERT(state != NULL && iop != NULL);
533 
534 	error = EINVAL;
535 	len = 0;
536 
537 	switch (iop->ioc_cmd) {
538 	case PPPIO_XFCS:
539 		/* Check for valid option length */
540 		if (iop->ioc_count != sizeof (uint32_t) || mp->b_cont == NULL)
541 			break;
542 
543 		/* Grab flag value */
544 		flagval = *(uint32_t *)mp->b_cont->b_rptr;
545 		if (flagval < PPPFCS_16 || flagval > PPPFCS_NONE)
546 			break;
547 		state->sa_flags &= ~SAF_XMITCRC32 & ~SAF_XMITCRCNONE;
548 		if (flagval == PPPFCS_32) {
549 #ifdef REPORT_CRC_TYPE
550 			KSET(pks_outcrctype, 32);
551 #endif
552 			state->sa_flags |= SAF_XMITCRC32;
553 		} else if (flagval == PPPFCS_NONE) {
554 #ifdef REPORT_CRC_TYPE
555 			KSET(pks_outcrctype, 0);
556 #endif
557 			state->sa_flags |= SAF_XMITCRCNONE;
558 		}
559 #ifdef REPORT_CRC_TYPE
560 		else {
561 			KSET(pks_outcrctype, 16);
562 		}
563 #endif
564 
565 		/* Return success */
566 		error = 0;
567 		break;
568 
569 	case PPPIO_RFCS:
570 		/* Check for valid option length */
571 		if (iop->ioc_count != sizeof (uint32_t) || mp->b_cont == NULL)
572 			break;
573 
574 		/* Grab flag value */
575 		flagval = *(uint32_t *)mp->b_cont->b_rptr;
576 		if (flagval < PPPFCS_16 || flagval > PPPFCS_NONE)
577 			break;
578 		state->sa_flags &= ~SAF_RECVCRC32 & ~SAF_RECVCRCNONE;
579 		if (flagval == PPPFCS_32) {
580 #ifdef REPORT_CRC_TYPE
581 			KSET(pks_incrctype, 32);
582 #endif
583 			state->sa_flags |= SAF_RECVCRC32;
584 		} else if (flagval == PPPFCS_NONE) {
585 #ifdef REPORT_CRC_TYPE
586 			KSET(pks_incrctype, 0);
587 #endif
588 			state->sa_flags |= SAF_RECVCRCNONE;
589 		}
590 #ifdef REPORT_CRC_TYPE
591 		else {
592 			KSET(pks_incrctype, 16);
593 		}
594 #endif
595 
596 		/* Return success */
597 		error = 0;
598 		break;
599 
600 	case PPPIO_XACCM:
601 		/* Check for valid asyncmap length */
602 		if (iop->ioc_count < sizeof (uint32_t) ||
603 		    iop->ioc_count > sizeof (ext_accm) ||
604 		    mp->b_cont == NULL)
605 			break;
606 
607 		/* Copy user's asyncmap into our state structure. */
608 		bcopy((caddr_t)mp->b_cont->b_rptr,
609 		    (caddr_t)state->sa_xaccm, iop->ioc_count);
610 
611 		state->sa_xaccm[2] &= ~0x40000000;	/* don't escape 0x5e */
612 		state->sa_xaccm[3] |= 0x60000000;	/* escape 0x7d, 0x7e */
613 
614 		error = 0;
615 		break;
616 
617 	case PPPIO_RACCM:
618 		/* Check for valid asyncmap length (only ctrl chars) */
619 		if (iop->ioc_count != sizeof (uint32_t) ||
620 		    mp->b_cont == NULL)
621 			break;
622 
623 		state->sa_raccm = *(uint32_t *)mp->b_cont->b_rptr;
624 
625 		error = 0;
626 		break;
627 
628 	case PPPIO_LASTMOD:
629 		/* We already know this. */
630 		state->sa_flags |= SAF_LASTMOD;
631 		error = 0;
632 		break;
633 
634 	case PPPIO_MUX:
635 		/* set the compression flags */
636 		if (iop->ioc_count != 2 * sizeof (uint32_t) ||
637 		    mp->b_cont == NULL)
638 			break;
639 
640 		/* set the mux flags */
641 		mux_flags = ((uint32_t *)mp->b_cont->b_rptr)[0];
642 		mask = ((uint32_t *)mp->b_cont->b_rptr)[1];
643 		if (mux_flags != 0)
644 			state->sa_flags = (state->sa_flags & ~mask) | (mask);
645 
646 		/* set the multiplexing timer value */
647 		if (mask & R_MUXMASK)
648 			state->sa_timeout_usec = mux_flags;
649 
650 		error = 0;
651 		break;
652 
653 	case PPPIO_CFLAGS:
654 		if (iop->ioc_count != 2 * sizeof (uint32_t) ||
655 		    mp->b_cont == NULL)
656 			break;
657 
658 		flagval = (((uint32_t *)mp->b_cont->b_rptr)[0] << 20) &
659 		    (SAF_RDECOMP_PROT | SAF_RDECOMP_AC | SAF_XCOMP_PROT |
660 		    SAF_XCOMP_AC);
661 		flagmask = (((uint32_t *)mp->b_cont->b_rptr)[1] << 20) &
662 		    (SAF_RDECOMP_PROT | SAF_RDECOMP_AC | SAF_XCOMP_PROT |
663 		    SAF_XCOMP_AC);
664 		state->sa_flags = flagval | (state->sa_flags & ~flagmask);
665 		*(uint32_t *)mp->b_cont->b_rptr = state->sa_flags >> 20;
666 		len = sizeof (uint32_t);
667 		error = 0;
668 		break;
669 
670 	case PPPIO_DEBUG:
671 		if (iop->ioc_count != sizeof (uint32_t) || mp->b_cont == NULL)
672 			break;
673 
674 		flagval = *(uint32_t *)mp->b_cont->b_rptr;
675 		if (flagval != PPPDBG_LOG + PPPDBG_AHDLC) {
676 			putnext(q, mp);
677 			return;
678 		}
679 		cmn_err(CE_CONT, AHDLC_MOD_NAME "%d: debug log enabled\n",
680 		    state->sa_unit);
681 		state->sa_flags |= SAF_XMITDUMP | SAF_RECVDUMP;
682 		error = 0;
683 		break;
684 	}
685 
686 	if (error == 0) {
687 		/* Success; tell the user */
688 		if (mp->b_cont == NULL)
689 			len = 0;
690 		else
691 			mp->b_cont->b_wptr = mp->b_cont->b_rptr + len;
692 		miocack(q, mp, len, 0);
693 	} else {
694 		/* Failure; send error back upstream. */
695 		KINCR(pks_ioctlserr);
696 		miocnak(q, mp, 0, error);
697 	}
698 }
699 
700 /*
701  * spppasyn_inner_mctl
702  *
703  * MT-Perimeters:
704  *	exclusive inner
705  *
706  * Handle state-affecting M_CTL messages.
707  */
708 static void
709 spppasyn_inner_mctl(queue_t *q, mblk_t *mp)
710 {
711 	sppp_ahdlc_t	*state;
712 	int		msglen;
713 	int		error;
714 
715 	ASSERT(q != NULL && mp != NULL);
716 	state = (sppp_ahdlc_t *)q->q_ptr;
717 	ASSERT(state != NULL);
718 
719 	msglen = MBLKL(mp);
720 	error = 0;
721 	switch (*mp->b_rptr) {
722 	case PPPCTL_MTU:
723 				/* Just ignore the MTU */
724 		break;
725 
726 	case PPPCTL_MRU:
727 		if (msglen != 4)
728 			error = EINVAL;
729 		else
730 			state->sa_mru =
731 			    ((ushort_t *)mp->b_rptr)[1];
732 		break;
733 
734 	case PPPCTL_UNIT:
735 		if (state->sa_ksp != NULL) {
736 			error = EINVAL;
737 			break;
738 		}
739 		if (msglen == 2)
740 			state->sa_unit = mp->b_rptr[1];
741 		else if (msglen == 8)
742 			state->sa_unit =
743 			    ((uint32_t *)mp->b_rptr)[1];
744 		else
745 			error = EINVAL;
746 		if (error == 0 && state->sa_ksp == NULL)
747 			create_kstats(state);
748 		break;
749 	}
750 
751 	if (error > 0) {
752 		KINCR(pks_ctlserr);
753 	}
754 	if (state->sa_flags & SAF_LASTMOD) {
755 		freemsg(mp);
756 	} else {
757 		KINCR(pks_ctlsfwd);
758 		putnext(q, mp);
759 	}
760 }
761 
762 /*
763  * spppasyn_wput()
764  *
765  * MT-Perimeters:
766  *	exclusive inner.
767  *
768  * Write side put routine.  This called by the modules above us (likely to
769  * be the compression module) to transmit data or pass along ioctls.
770  */
771 static int
772 spppasyn_wput(queue_t *q, mblk_t *mp)
773 {
774 	sppp_ahdlc_t		*state;
775 	struct iocblk		*iop;
776 	int			error;
777 	mblk_t			*np;
778 	struct ppp_stats64	*psp;
779 	int			msglen;
780 
781 	ASSERT(q != NULL && mp != NULL);
782 	state = (sppp_ahdlc_t *)q->q_ptr;
783 	ASSERT(state != NULL);
784 
785 	switch (MTYPE(mp)) {
786 
787 	case M_DATA:
788 		/*
789 		 * A data packet - do character-stuffing and FCS, and
790 		 * send it onwards.  The blocks are freed as we go.
791 		 */
792 		if (IS_XMUX_ENABLED(state))
793 			mp = spppasyn_muxencode(q, mp);
794 		else
795 			mp = ahdlc_encode(q, mp);
796 		if (mp != NULL)
797 			putnext(q, mp);
798 		break;
799 
800 	case M_IOCTL:
801 
802 		KINCR(pks_ioctls);
803 		iop = (struct iocblk *)mp->b_rptr;
804 
805 		msglen = 0;
806 
807 		switch (iop->ioc_cmd) {
808 		case PPPIO_XFCS:
809 		case PPPIO_RFCS:
810 		case PPPIO_XACCM:
811 		case PPPIO_RACCM:
812 		case PPPIO_LASTMOD:
813 		case PPPIO_DEBUG:
814 		case PPPIO_MUX:
815 		case PPPIO_CFLAGS:
816 			spppasyn_inner_ioctl(q, mp);
817 			return (0);
818 
819 		case PPPIO_GCLEAN:
820 			np = allocb(sizeof (uint32_t), BPRI_HI);
821 			if (np == NULL) {
822 				error = ENOSR;
823 				break;
824 			}
825 			if (mp->b_cont != NULL) {
826 				freemsg(mp->b_cont);
827 			}
828 			mp->b_cont = np;
829 
830 			*(uint32_t *)np->b_wptr = state->sa_flags & RCV_FLAGS;
831 
832 			msglen = sizeof (uint32_t);
833 			np->b_wptr += msglen;
834 			error = 0;
835 			break;
836 
837 		case PPPIO_GETSTAT:
838 			error = EINVAL;
839 			break;
840 
841 		case PPPIO_GETSTAT64:
842 			np = allocb(sizeof (*psp), BPRI_HI);
843 			if (np == NULL) {
844 				error = ENOSR;
845 				break;
846 			}
847 			if (mp->b_cont != NULL) {
848 				freemsg(mp->b_cont);
849 			}
850 			mp->b_cont = np;
851 
852 			psp = (struct ppp_stats64 *)np->b_wptr;
853 			bzero((caddr_t)psp, sizeof (*psp));
854 			psp->p = state->sa_stats;
855 
856 			msglen = sizeof (*psp);
857 			np->b_wptr += msglen;
858 			error = 0;
859 			break;
860 
861 		case PPPIO_GTYPE:
862 			np = allocb(sizeof (uint32_t), BPRI_HI);
863 			if (np == NULL) {
864 				error = ENOSR;
865 				break;
866 			}
867 			if (mp->b_cont != NULL) {
868 				freemsg(mp->b_cont);
869 			}
870 			mp->b_cont = np;
871 
872 			*(uint32_t *)np->b_wptr = PPPTYP_AHDLC;
873 
874 			msglen = sizeof (uint32_t);
875 			np->b_wptr += msglen;
876 			error = 0;
877 			break;
878 
879 		default:
880 			/* Unknown ioctl -- forward along */
881 			KINCR(pks_ioctlsfwd);
882 			putnext(q, mp);
883 			return (0);
884 		}
885 
886 		if (error == 0) {
887 			/* Success; tell the user */
888 			miocack(q, mp, msglen, 0);
889 		} else {
890 			/* Failure; send error back upstream. */
891 			KINCR(pks_ioctlserr);
892 			miocnak(q, mp, 0, error);
893 		}
894 
895 		break;
896 
897 	case M_CTL:
898 		KINCR(pks_ctls);
899 		spppasyn_inner_mctl(q, mp);
900 		break;
901 
902 	default:
903 		if (state->sa_flags & (SAF_XMITDUMP|SAF_RECVDUMP))
904 			cmn_err(CE_CONT,
905 			    "spppasyn_wpur:  unknown buffer type %d",
906 			    MTYPE(mp));
907 		KINCR(pks_unknownwrs);
908 		putnext(q, mp);
909 		break;
910 	}
911 
912 	return (0);
913 }
914 
915 /*
916  * spppasyn_rput()
917  *
918  * MT-Perimeters:
919  *	exclusive inner.
920  *
921  * Read side put routine.  This is called by the async serial driver
922  * below us to handle received data and returned signals (like
923  * hang-up).
924  */
925 static int
926 spppasyn_rput(queue_t *q, mblk_t  *mp)
927 {
928 	sppp_ahdlc_t	*state;
929 	mblk_t		*mpnext;
930 
931 	ASSERT(q != NULL && mp != NULL);
932 	state = (sppp_ahdlc_t *)q->q_ptr;
933 	ASSERT(state != NULL);
934 
935 	switch (MTYPE(mp)) {
936 
937 	case M_DATA:
938 		/* Note -- decoder frees the buffers */
939 		mp = ahdlc_decode(q, mp);
940 		while (mp != NULL) {
941 			mpnext = mp->b_next;
942 			mp->b_next = NULL;
943 			putnext(q, mp);
944 			mp = mpnext;
945 		}
946 		break;
947 
948 	case M_HANGUP:
949 		KINCR(pks_hangups);
950 		state->sa_flags |= SAF_IFLUSH;
951 		putnext(q, mp);
952 		break;
953 
954 	default:
955 		if (state->sa_flags & (SAF_XMITDUMP|SAF_RECVDUMP)) {
956 			if (MTYPE(mp) == M_IOCTL)
957 				cmn_err(CE_CONT,
958 				    "spppasyn_rput:  unexpected ioctl %X",
959 				    ((struct iocblk *)mp->b_rptr)->ioc_cmd);
960 			else
961 				cmn_err(CE_CONT,
962 				    "spppasyn_rput:  unknown buffer type %d",
963 				    MTYPE(mp));
964 		}
965 		KINCR(pks_unknownrds);
966 		putnext(q, mp);
967 		break;
968 	}
969 
970 	return (0);
971 }
972 
973 /*
974  * ahdlc_encode
975  *
976  * Perform asynchronous HDLC framing on a given buffer and transmit
977  * the result.  The state structure must be valid.  The input buffers
978  * are freed as we go.
979  *
980  * This function is called by wput and just encodes the data.  Wput
981  * then calls putnext directly.  There's no service routine for this
982  * module, so flow control is asserted by the module below us up to
983  * our caller by the STREAMS framework.  This is by design -- this
984  * module does not queue anything so that other modules can make QoS
985  * decisions.
986  */
987 static mblk_t *
988 ahdlc_encode(queue_t *q, mblk_t	*mp)
989 {
990 	sppp_ahdlc_t	*state;
991 	uint32_t	loc_xaccm[8];
992 	ushort_t	fcs16;
993 	uint32_t	fcs32;
994 	size_t		msglen;
995 	size_t		outmp_len;
996 	mblk_t		*outmp;
997 	mblk_t		*curout;
998 	mblk_t		*tmp;
999 	uchar_t		*ep;
1000 	uchar_t		*dp;
1001 	uchar_t		*tp;
1002 	uchar_t		*tpmax;
1003 #if defined(lint) || defined(_lint)
1004 	uchar_t		chr;	/* lint likes this */
1005 #else
1006 	int		chr;	/* not uchar_t; more efficient this way */
1007 				/* with WorkShop compiler */
1008 #endif
1009 	int		is_lcp, is_ctrl;
1010 	int		code;
1011 	hrtime_t	hrtime;
1012 	uint32_t	flags;	/* sampled copy of flags */
1013 
1014 	state = (sppp_ahdlc_t *)q->q_ptr;
1015 
1016 	/* Don't transmit anything obviously silly. */
1017 	msglen = msgsize(mp);
1018 	if (msglen < 4) {
1019 		KINCR(pks_outrunts);
1020 		freemsg(mp);
1021 		(void) putnextctl1(RD(q), M_CTL, PPPCTL_OERROR);
1022 		return (NULL);
1023 	}
1024 
1025 	/*
1026 	 * Allocate an output buffer just large enough for most cases.
1027 	 * Based on original work in the ppp-2.2 AIX PPP driver, we
1028 	 * estimate the output size as 1.25 * input message length
1029 	 * plus 16.  If this turns out to be too small, then we'll
1030 	 * allocate exactly one additional buffer with two times the
1031 	 * remaining input length (the maximum that could possibly be
1032 	 * required).
1033 	 */
1034 	outmp_len = msglen + (msglen >> 2) + 16;
1035 	outmp = allocb(outmp_len, BPRI_MED);
1036 	if (outmp == NULL)
1037 		goto outallocfail;
1038 
1039 	tp = outmp->b_wptr;
1040 
1041 	/*
1042 	 * Check if our last transmit happened within FLAG_TIME, using
1043 	 * the system's hrtime.
1044 	 */
1045 	hrtime = gethrtime();
1046 	if (ABS(hrtime - state->sa_hrtime) > FLAG_TIME) {
1047 		*tp++ = PPP_FLAG;
1048 	}
1049 	state->sa_hrtime = hrtime;
1050 	bcopy((caddr_t)state->sa_xaccm, (caddr_t)loc_xaccm, sizeof (loc_xaccm));
1051 	flags = state->sa_flags;
1052 
1053 	/*
1054 	 * LCP messages must be sent using the default escaping
1055 	 * (ACCM).  We bend this rule a little to allow LCP
1056 	 * Echo-Request through with the negotiated escaping so that
1057 	 * we can detect bad negotiated ACCM values.  If the ACCM is
1058 	 * bad, echos will fail and take down the link.
1059 	 */
1060 	is_lcp = is_ctrl = 0;
1061 	code = MSG_BYTE(mp, 0);
1062 	if (code == PPP_ALLSTATIONS) {
1063 		if (MSG_BYTE(mp, 1) == PPP_UI) {
1064 			code = MSG_BYTE(mp, 2);
1065 			if (code == (PPP_LCP >> 8) &&
1066 			    MSG_BYTE(mp, 3) == (PPP_LCP & 0xFF)) {
1067 				if (LCP_USE_DFLT(mp))
1068 					is_lcp = 2;
1069 				else
1070 					is_lcp = 1;	/* Echo-Request */
1071 			} else if (!(code & 1) && code > 0x3F)
1072 				is_ctrl = 1;
1073 		}
1074 	} else if (!(code & 1) && code > 0x3F)
1075 		is_ctrl = 1;
1076 
1077 	/*
1078 	 * If it's LCP and not just an LCP Echo-Request, then we need
1079 	 * to drop back to default escaping rules temporarily.
1080 	 */
1081 	if (is_lcp > 1) {
1082 		/*
1083 		 * force escape on 0x00 through 0x1f
1084 		 * and, for RFC 1662 (and ISO 3309:1991), 0x80-0x9f.
1085 		 */
1086 		loc_xaccm[0] = 0xffffffff;
1087 		loc_xaccm[4] = 0xffffffff;
1088 	}
1089 
1090 	fcs16 = PPPINITFCS16;		/* Initial FCS is 0xffff */
1091 	fcs32 = PPPINITFCS32;
1092 
1093 	/*
1094 	 * Process this block and the rest (if any) attached to this
1095 	 * one.  Note that we quite intentionally ignore the type of
1096 	 * the buffer.  The caller has checked that the first buffer
1097 	 * is M_DATA; all others must be so, and any that are not are
1098 	 * harmless driver errors.
1099 	 */
1100 	curout = outmp;
1101 	tpmax = outmp->b_datap->db_lim;
1102 	do {
1103 		dp = mp->b_rptr;
1104 		while (dp < (ep = mp->b_wptr)) {
1105 			/*
1106 			 * Calculate maximum safe run length for inner loop,
1107 			 * regardless of escaping.
1108 			 */
1109 			outmp_len = (tpmax - tp) / 2;
1110 			if (dp + outmp_len < ep)
1111 				ep = dp + outmp_len;
1112 
1113 			/*
1114 			 * Select out on CRC type here to make the
1115 			 * inner byte loop more efficient.  (We could
1116 			 * do both CRCs at all times if we wanted, but
1117 			 * that ends up taking an extra 8 cycles per
1118 			 * byte -- 47% overhead!)
1119 			 */
1120 			if (flags & SAF_XMITCRC32) {
1121 				while (dp < ep) {
1122 					chr = *dp++;
1123 					fcs32 = PPPFCS32(fcs32, chr);
1124 					if (IN_TX_MAP(chr, loc_xaccm)) {
1125 						*tp++ = PPP_ESCAPE;
1126 						chr ^= PPP_TRANS;
1127 					}
1128 					*tp++ = chr;
1129 				}
1130 			} else {
1131 				while (dp < ep) {
1132 					chr = *dp++;
1133 					fcs16 = PPPFCS16(fcs16, chr);
1134 					if (IN_TX_MAP(chr, loc_xaccm)) {
1135 						*tp++ = PPP_ESCAPE;
1136 						chr ^= PPP_TRANS;
1137 					}
1138 					*tp++ = chr;
1139 				}
1140 			}
1141 
1142 			/*
1143 			 * If we limited our run length and we're now low
1144 			 * on output space, then allocate a new output buffer.
1145 			 * This should rarely happen, unless the output data
1146 			 * has a lot of escapes.
1147 			 */
1148 			if (ep != mp->b_wptr && tpmax - tp < 5) {
1149 				KINCR(pks_extrabufs);
1150 				/* Get remaining message length */
1151 				outmp_len = (mp->b_wptr - dp) +
1152 				    msgsize(mp->b_cont);
1153 				/* Calculate maximum required space */
1154 				outmp_len = (outmp_len + PPP_FCS32LEN) * 2 + 1;
1155 				curout = allocb(outmp_len, BPRI_MED);
1156 				if ((outmp->b_cont = curout) == NULL)
1157 					goto outallocfail;
1158 				outmp->b_wptr = tp;
1159 				tp = curout->b_wptr;
1160 				tpmax = curout->b_datap->db_lim;
1161 			}
1162 		}
1163 		tmp = mp->b_cont;
1164 		freeb(mp);
1165 		mp = tmp;
1166 	} while (mp != NULL);
1167 
1168 	/*
1169 	 * Make sure we have enough remaining room to add the CRC (if
1170 	 * any) and a trailing flag byte.
1171 	 */
1172 	outmp_len = PPP_FCS32LEN * 2 + 1;
1173 	if (tpmax - tp < outmp_len) {
1174 		KINCR(pks_extrabufs);
1175 		curout = allocb(outmp_len, BPRI_MED);
1176 		if ((outmp->b_cont = curout) == NULL)
1177 			goto outallocfail;
1178 		outmp->b_wptr = tp;
1179 		tp = curout->b_wptr;
1180 		tpmax = curout->b_datap->db_lim;
1181 	}
1182 
1183 	/*
1184 	 * Network layer data is the only thing that can be sent with
1185 	 * no CRC at all.
1186 	 */
1187 	if ((flags & SAF_XMITCRCNONE) && !is_lcp && !is_ctrl)
1188 		goto nocrc;
1189 
1190 	if (!(flags & SAF_XMITCRC32))
1191 		fcs32 = fcs16;
1192 
1193 	/*
1194 	 * Append the HDLC FCS, making sure that escaping is done on any
1195 	 * necessary bytes. Note that the FCS bytes are in little-endian.
1196 	 */
1197 	fcs32 = ~fcs32;
1198 	chr = fcs32 & 0xff;
1199 	if (IN_TX_MAP(chr, loc_xaccm)) {
1200 		*tp++ = PPP_ESCAPE;
1201 		chr ^= PPP_TRANS;
1202 	}
1203 	*tp++ = chr;
1204 
1205 	chr = (fcs32 >> 8) & 0xff;
1206 	if (IN_TX_MAP(chr, loc_xaccm)) {
1207 		*tp++ = PPP_ESCAPE;
1208 		chr ^= PPP_TRANS;
1209 	}
1210 	*tp++ = chr;
1211 
1212 	if (flags & SAF_XMITCRC32) {
1213 		chr = (fcs32 >> 16) & 0xff;
1214 		if (IN_TX_MAP(chr, loc_xaccm)) {
1215 			*tp++ = PPP_ESCAPE;
1216 			chr ^= PPP_TRANS;
1217 		}
1218 		*tp++ = chr;
1219 
1220 		chr = (fcs32 >> 24) & 0xff;
1221 		if (IN_TX_MAP(chr, loc_xaccm)) {
1222 			*tp++ = PPP_ESCAPE;
1223 			chr ^= PPP_TRANS;
1224 		}
1225 		*tp++ = chr;
1226 	}
1227 
1228 nocrc:
1229 	/*
1230 	 * And finally append the HDLC flag, and send it away
1231 	 */
1232 	*tp++ = PPP_FLAG;
1233 	ASSERT(tp < tpmax);
1234 	curout->b_wptr = tp;
1235 
1236 	state->sa_stats.ppp_obytes += msgsize(outmp);
1237 	state->sa_stats.ppp_opackets++;
1238 
1239 	if (state->sa_flags & SAF_XMITDUMP)
1240 		ppp_dump_frame(state, outmp, "sent");
1241 
1242 	KINCR(pks_dataout);
1243 	return (outmp);
1244 
1245 outallocfail:
1246 	KINCR(pks_outallocfails);
1247 	state->sa_stats.ppp_oerrors++;
1248 	freemsg(outmp);
1249 	freemsg(mp);
1250 	(void) putnextctl1(RD(q), M_CTL, PPPCTL_OERROR);
1251 	return (NULL);
1252 }
1253 
1254 /*
1255  * Handle end-of-frame excitement.  This is here mostly because the Solaris
1256  * C style rules require tab for indent and prohibit excessive indenting.
1257  */
1258 static mblk_t *
1259 receive_frame(queue_t *q, mblk_t *outmp, ushort_t fcs16, uint32_t fcs32)
1260 {
1261 	sppp_ahdlc_t *state = (sppp_ahdlc_t *)q->q_ptr;
1262 	uchar_t *cp, *ep;
1263 	int is_lcp, is_ctrl, crclen;
1264 	ushort_t 	proto;
1265 	int i;
1266 
1267 	cp = outmp->b_rptr;
1268 	if (cp[0] == PPP_ALLSTATIONS && cp[1] == PPP_UI)
1269 		cp += 2;
1270 	proto = *cp++;
1271 	if ((proto & 1) == 0)
1272 		proto = (proto << 8) + *cp++;
1273 	is_lcp = (proto == PPP_LCP);
1274 	is_ctrl = (proto >= 0x4000);
1275 
1276 	/*
1277 	 * To allow for renegotiation, LCP accepts good CRCs of either
1278 	 * type at any time.  Other control (non-network) packets must
1279 	 * have either CRC-16 or CRC-32, as negotiated.  Network layer
1280 	 * packets may additionally omit the CRC entirely, if that was
1281 	 * negotiated.
1282 	 */
1283 	if ((is_lcp && (fcs16 == PPPGOODFCS16 || fcs32 == PPPGOODFCS32)) ||
1284 	    ((fcs16 == PPPGOODFCS16 && !(state->sa_flags & SAF_RECVCRC32)) ||
1285 	    (fcs32 == PPPGOODFCS32 &&
1286 	    (state->sa_flags & SAF_RECVCRC32))) ||
1287 	    (!is_ctrl && !is_lcp && (state->sa_flags & SAF_RECVCRCNONE))) {
1288 
1289 		state->sa_stats.ppp_ipackets++;
1290 		if (is_lcp) {
1291 			crclen = (fcs16 == PPPGOODFCS16) ?
1292 			    PPP_FCSLEN : PPP_FCS32LEN;
1293 		} else {
1294 			crclen = (state->sa_flags & SAF_RECVCRC32) ?
1295 			    PPP_FCS32LEN : PPP_FCSLEN;
1296 			if (!is_ctrl && (state->sa_flags & SAF_RECVCRCNONE))
1297 				crclen = 0;
1298 		}
1299 		if (crclen != 0) {
1300 			i = adjmsg(outmp, -crclen);
1301 			ASSERT(i != 0);
1302 #if defined(lint) || defined(_lint)
1303 			/* lint is happier this way in a non-DEBUG build */
1304 			i = i;
1305 #endif
1306 		}
1307 
1308 		if (proto == PPP_MUX) {
1309 			/* spppasyn_inpkt checks for PPP_MUX packets */
1310 			KINCR(pks_recvmux);
1311 			/* Remove headers */
1312 			outmp->b_rptr = cp;
1313 			return (spppasyn_inpkt(q, outmp));
1314 		}
1315 
1316 		/*
1317 		 * Sniff the received data stream.  If we see an LCP
1318 		 * Configure-Ack, then pick out the ACCM setting, if
1319 		 * any, and configure now.  This allows us to stay in
1320 		 * sync in case the peer is already out of Establish
1321 		 * phase.
1322 		 */
1323 		if (is_lcp && *cp == 2) {
1324 			ep = outmp->b_wptr;
1325 			i = (cp[2] << 8) | cp[3];
1326 			if (i > ep - cp)
1327 				ep = cp;	/* Discard junk */
1328 			else if (i < ep - cp)
1329 				ep = cp + i;
1330 			cp += 4;
1331 			while (cp + 2 < ep) {
1332 				if ((i = cp[1]) < 2)
1333 					i = 2;
1334 				if (cp + i > ep)
1335 					i = ep - cp;
1336 				if (cp[0] == 2 && i >= 6) {
1337 					state->sa_raccm = (cp[2] << 24) |
1338 					    (cp[3] << 16) | (cp[4] << 8) |
1339 					    cp[5];
1340 					break;
1341 				}
1342 				cp += i;
1343 			}
1344 		}
1345 		return (outmp);
1346 	} else {
1347 		KINCR(pks_incrcerrs);
1348 		cmn_err(CE_CONT, PPP_DRV_NAME "%d: bad fcs (len=%ld)\n",
1349 		    state->sa_unit, msgsize(outmp));
1350 
1351 		if (state->sa_flags & SAF_RECVDUMP)
1352 			ppp_dump_frame(state, outmp, "bad data");
1353 
1354 		freemsg(outmp);
1355 
1356 		state->sa_stats.ppp_ierrors++;
1357 
1358 		(void) putnextctl1(q, M_CTL, PPPCTL_IERROR);
1359 		return (NULL);
1360 	}
1361 }
1362 
1363 /*
1364  * ahdlc_decode()
1365  *
1366  * Process received characters.
1367  *
1368  * This is handled as exclusive inner so that we don't get confused
1369  * about the state.  Returns a list of packets linked by b_next.
1370  */
1371 static mblk_t *
1372 ahdlc_decode(queue_t *q, mblk_t  *mp)
1373 {
1374 	sppp_ahdlc_t	*state;
1375 	mblk_t		*retmp;		/* list of packets to return */
1376 	mblk_t		*outmp;		/* buffer for decoded data */
1377 	mblk_t		*mpnext;	/* temporary ptr for unlinking */
1378 	uchar_t		*dp;		/* pointer to input data */
1379 	uchar_t		*dpend;		/* end of input data */
1380 	uchar_t		*tp;		/* pointer to decoded output data */
1381 	uchar_t		*tpmax;		/* output buffer limit */
1382 	int		flagtmp;	/* temporary cache of flags */
1383 #if defined(lint) || defined(_lint)
1384 	uchar_t		chr;	/* lint likes this */
1385 #else
1386 	int		chr;	/* not uchar_t; more efficient this way */
1387 				/* with WorkShop compiler */
1388 #endif
1389 	ushort_t	fcs16;		/* running CRC-16 */
1390 	uint32_t	fcs32;		/* running CRC-32 */
1391 #ifdef HANDLE_ZERO_LENGTH
1392 	size_t		nprocessed;
1393 #endif
1394 
1395 	state = (sppp_ahdlc_t *)q->q_ptr;
1396 
1397 	KINCR(pks_datain);
1398 
1399 	state->sa_stats.ppp_ibytes += msgsize(mp);
1400 
1401 	if (state->sa_flags & SAF_RECVDUMP)
1402 		ppp_dump_frame(state, mp, "rcvd");
1403 
1404 	flagtmp = state->sa_flags;
1405 	fcs16 = state->sa_infcs16;
1406 	fcs32 = state->sa_infcs32;
1407 	outmp = state->sa_rx_buf;
1408 	if (outmp == NULL) {
1409 		tp = tpmax = NULL;
1410 	} else {
1411 		tp = outmp->b_wptr;
1412 		tpmax = outmp->b_datap->db_lim;
1413 	}
1414 #ifdef HANDLE_ZERO_LENGTH
1415 	nprocessed = 0;
1416 #endif
1417 
1418 	/*
1419 	 * Main input processing loop.  Loop over received buffers and
1420 	 * each byte in each buffer.  Note that we quite intentionally
1421 	 * ignore the type of the buffer.  The caller has checked that
1422 	 * the first buffer is M_DATA; all others must be so, and any
1423 	 * that are not are harmless driver errors.
1424 	 */
1425 	retmp = NULL;
1426 	while (mp != NULL) {
1427 
1428 		/* Innermost loop -- examine bytes in buffer. */
1429 		dpend = mp->b_wptr;
1430 		dp = mp->b_rptr;
1431 #ifdef HANDLE_ZERO_LENGTH
1432 		nprocessed += dpend - dp;
1433 #endif
1434 		for (; dp < dpend; dp++) {
1435 			chr = *dp;
1436 
1437 			/*
1438 			 * This should detect the lack of an 8-bit
1439 			 * communication channel, which is necessary
1440 			 * for PPP to work.
1441 			 */
1442 			flagtmp |= charflags[chr];
1443 
1444 			/*
1445 			 * So we have a HDLC flag ...
1446 			 */
1447 			if (chr == PPP_FLAG) {
1448 
1449 				/*
1450 				 * If there's no received buffer, then
1451 				 * just ignore this frame marker.
1452 				 */
1453 				if ((flagtmp & SAF_IFLUSH) || outmp == NULL) {
1454 					flagtmp &= ~SAF_IFLUSH & ~SAF_ESCAPED;
1455 					continue;
1456 				}
1457 
1458 				/*
1459 				 * Per RFC 1662 -- silently discard
1460 				 * runt frames (fewer than 4 octets
1461 				 * with 16 bit CRC) and frames that
1462 				 * end in 7D 7E (abort sequence).
1463 				 * These are not counted as errors.
1464 				 *
1465 				 * (We could just reset the pointers
1466 				 * and reuse the buffer, but this is a
1467 				 * rarely used error path and not
1468 				 * worth the optimization.)
1469 				 */
1470 				if ((flagtmp & SAF_ESCAPED) ||
1471 				    tp - outmp->b_rptr < 2 + PPP_FCSLEN) {
1472 					if (flagtmp & SAF_ESCAPED)
1473 						KINCR(pks_inaborts);
1474 					else
1475 						KINCR(pks_inrunts);
1476 					if (state->sa_flags & SAF_RECVDUMP) {
1477 						outmp->b_wptr = tp;
1478 						ppp_dump_frame(state, outmp,
1479 						    "runt");
1480 					}
1481 					freemsg(outmp);
1482 					flagtmp &= ~SAF_ESCAPED;
1483 				} else {
1484 					/* Handle the received frame */
1485 					outmp->b_wptr = tp;
1486 					outmp = receive_frame(q, outmp, fcs16,
1487 					    fcs32);
1488 					retmp = sppp_mappend(retmp, outmp);
1489 				}
1490 
1491 				outmp = NULL;
1492 				tp = tpmax = NULL;
1493 
1494 				continue;
1495 			}
1496 
1497 			/* If we're waiting for a new frame, then drop data. */
1498 			if (flagtmp & SAF_IFLUSH) {
1499 				continue;
1500 			}
1501 
1502 			/*
1503 			 * Start of new frame.  Allocate a receive
1504 			 * buffer large enough to store a frame (after
1505 			 * un-escaping) of at least 1500 octets plus
1506 			 * the CRC.  If MRU is negotiated to be more
1507 			 * than the default, then allocate that much.
1508 			 * In addition, we add an extra 32-bytes for a
1509 			 * fudge factor, in case the peer doesn't do
1510 			 * arithmetic very well.
1511 			 */
1512 			if (outmp == NULL) {
1513 				int maxlen;
1514 
1515 				if ((maxlen = state->sa_mru) < PPP_MRU)
1516 					maxlen = PPP_MRU;
1517 				maxlen += PPP_FCS32LEN + 32;
1518 				outmp = allocb(maxlen, BPRI_MED);
1519 
1520 				/*
1521 				 * If allocation fails, try again on
1522 				 * the next frame.  (Go into discard
1523 				 * mode.)
1524 				 */
1525 				if (outmp == NULL) {
1526 					KINCR(pks_inallocfails);
1527 					flagtmp |= SAF_IFLUSH;
1528 					continue;
1529 				}
1530 
1531 				tp = outmp->b_wptr;
1532 				tpmax = outmp->b_datap->db_lim;
1533 
1534 				/* Neither flag can possibly be set here. */
1535 				flagtmp &= ~(SAF_IFLUSH | SAF_ESCAPED);
1536 				fcs16 = PPPINITFCS16;
1537 				fcs32 = PPPINITFCS32;
1538 			}
1539 
1540 			/*
1541 			 * If the peer sends us a character that's in
1542 			 * our receive character map, then that's
1543 			 * junk.  Discard it without changing state.
1544 			 * If he previously sent us an escape
1545 			 * character, then toggle this one and
1546 			 * continue.  Otherwise, if he's now sending
1547 			 * escape, set the flag for next time.
1548 			 */
1549 			if (IN_RX_MAP(chr, state->sa_raccm)) {
1550 				KINCR(pks_inbadchars);
1551 				KOR(pks_inbadcharmask, 1 << chr);
1552 				continue;
1553 			}
1554 			if (flagtmp & SAF_ESCAPED) {
1555 				chr ^= PPP_TRANS;
1556 				flagtmp &= ~SAF_ESCAPED;
1557 			} else if (chr == PPP_ESCAPE) {
1558 				flagtmp |= SAF_ESCAPED;
1559 				continue;
1560 			}
1561 
1562 			/*
1563 			 * Unless the peer is confused about the
1564 			 * negotiated MRU, we should never get a frame
1565 			 * that is too long.  If it happens, toss it
1566 			 * away and begin discarding data until we see
1567 			 * the end of the frame.
1568 			 */
1569 			if (tp < tpmax) {
1570 				fcs16 = PPPFCS16(fcs16, chr);
1571 				fcs32 = PPPFCS32(fcs32, chr);
1572 				*tp++ = chr;
1573 			} else {
1574 				KINCR(pks_intoolongs);
1575 				cmn_err(CE_CONT, PPP_DRV_NAME
1576 				    "%d: frame too long (%d bytes)\n",
1577 				    state->sa_unit,
1578 				    (int)(tpmax - outmp->b_rptr));
1579 
1580 				freemsg(outmp);
1581 				outmp = NULL;
1582 				tp = tpmax = NULL;
1583 				flagtmp |= SAF_IFLUSH;
1584 			}
1585 		}
1586 
1587 		/*
1588 		 * Free the buffer we just processed and move on to
1589 		 * the next one.
1590 		 */
1591 		mpnext = mp->b_cont;
1592 		freeb(mp);
1593 		mp = mpnext;
1594 	}
1595 	state->sa_flags = flagtmp;
1596 	if ((state->sa_rx_buf = outmp) != NULL)
1597 		outmp->b_wptr = tp;
1598 	state->sa_infcs16 = fcs16;
1599 	state->sa_infcs32 = fcs32;
1600 
1601 #ifdef HANDLE_ZERO_LENGTH
1602 	if (nprocessed <= 0) {
1603 		outmp = allocb(0, BPRI_MED);
1604 		if (outmp != NULL) {
1605 			outmp->b_datap->db_type = M_HANGUP;
1606 			retmp = sppp_mappend(retmp, outmp);
1607 		}
1608 	}
1609 #endif
1610 	return (retmp);
1611 }
1612 
1613 /*
1614  * Nifty packet dumper; copied from AIX 4.1 port.  This routine dumps
1615  * the raw received and transmitted data through syslog.  This allows
1616  * debug of communications problems without resorting to a line
1617  * analyzer.
1618  *
1619  * The expression "3*BYTES_PER_LINE" used frequently here represents
1620  * the size of each hex value printed -- two hex digits and a space.
1621  */
1622 #define	BYTES_PER_LINE	8
1623 static void
1624 ppp_dump_frame(sppp_ahdlc_t *state, mblk_t *mptr, const char *msg)
1625 {
1626 	/*
1627 	 * Buffer is big enough for hex digits, two spaces, ASCII output,
1628 	 * and one NUL byte.
1629 	 */
1630 	char buf[3 * BYTES_PER_LINE + 2 + BYTES_PER_LINE + 1];
1631 	uchar_t *rptr, *eptr;
1632 	int i, chr;
1633 	char *bp;
1634 	static const char digits[] = "0123456789abcdef";
1635 
1636 	cmn_err(CE_CONT, "!ppp_async%d: %s %ld bytes\n", state->sa_unit,
1637 	    msg, msgsize(mptr));
1638 	i = 0;
1639 	bp = buf;
1640 	/* Add filler spaces between hex output and ASCII */
1641 	buf[3 * BYTES_PER_LINE] = ' ';
1642 	buf[3 * BYTES_PER_LINE + 1] = ' ';
1643 	/* Add NUL byte at end */
1644 	buf[sizeof (buf) - 1] = '\0';
1645 	while (mptr != NULL) {
1646 		rptr = mptr->b_rptr; /* get pointer to beginning  */
1647 		eptr = mptr->b_wptr;
1648 		while (rptr < eptr) {
1649 			chr = *rptr++;
1650 			/* convert byte to ascii hex */
1651 			*bp++ = digits[chr >> 4];
1652 			*bp++ = digits[chr & 0xf];
1653 			*bp++ = ' ';
1654 			/* Insert ASCII past hex output and filler */
1655 			buf[3 * BYTES_PER_LINE + 2 + i] =
1656 			    (chr >= 0x20 && chr <= 0x7E) ? (char)chr : '.';
1657 			i++;
1658 			if (i >= BYTES_PER_LINE) {
1659 				cmn_err(CE_CONT, "!ppp%d: %s\n", state->sa_unit,
1660 				    buf);
1661 				bp = buf;
1662 				i = 0;
1663 			}
1664 		}
1665 		mptr = mptr->b_cont;
1666 	}
1667 	if (bp > buf) {
1668 		/* fill over unused hex display positions */
1669 		while (bp < buf + 3 * BYTES_PER_LINE)
1670 			*bp++ = ' ';
1671 		/* terminate ASCII string at right position */
1672 		buf[3 * BYTES_PER_LINE + 2 + i] = '\0';
1673 		cmn_err(CE_CONT, "!ppp%d: %s\n", state->sa_unit, buf);
1674 	}
1675 }
1676 
1677 static mblk_t *
1678 spppasyn_muxencode(queue_t *q, mblk_t *mp)
1679 {
1680 	sppp_ahdlc_t	*state = (sppp_ahdlc_t *)q->q_ptr;
1681 	uint32_t	len;
1682 	uint32_t	nlen;
1683 	ushort_t	protolen;
1684 	uint32_t	hdrlen;
1685 	ushort_t	proto;
1686 	mblk_t		*new_frame;
1687 	mblk_t		*tmp;
1688 	mblk_t		*send_frame;
1689 	ushort_t	i;
1690 
1691 	len = msgdsize(mp);
1692 	i = 0;
1693 	protolen = 1;
1694 	proto = MSG_BYTE(mp, i);
1695 
1696 	if (proto == PPP_ALLSTATIONS) {
1697 		len -= 2;
1698 		i += 2;
1699 		proto = MSG_BYTE(mp, i);
1700 	}
1701 
1702 	++i;
1703 	if ((proto & 1) == 0) {
1704 		proto = (proto << 8) + MSG_BYTE(mp, i);
1705 		protolen++;
1706 	}
1707 
1708 	hdrlen = i - 1;
1709 
1710 	send_frame = NULL;
1711 	if (len > PPP_MAX_MUX_LEN || (proto & 0x8000)) {
1712 
1713 		/* send the queued frames */
1714 		if (state->sa_mqhead != NULL) {
1715 			/* increment counter if it is MUX pkt */
1716 			if (state->sa_mqtail != NULL)
1717 				KINCR(pks_sentmux);
1718 			send_frame = ahdlc_encode(q, state->sa_mqhead);
1719 		}
1720 
1721 		/* send the current frame */
1722 		mp = ahdlc_encode(q, mp);
1723 		send_frame = sppp_mcat(send_frame, mp);
1724 
1725 		/* reset the state values over here */
1726 		RESET_MUX_VALUES(state);
1727 		return (send_frame);
1728 	}
1729 
1730 	/* len + 1 , since we add the mux overhead */
1731 	nlen = len + 1;
1732 	/* subtract the protocol length if protocol matches */
1733 	if (state->sa_proto == proto)
1734 		nlen -= protolen;
1735 
1736 	send_frame = NULL;
1737 	if ((state->sa_mqlen + nlen) >= state->sa_mru) {
1738 
1739 		/* send the existing queued frames */
1740 		if (state->sa_mqhead != NULL) {
1741 			/* increment counter if it is MUX pkt */
1742 			if (state->sa_mqtail != NULL)
1743 				KINCR(pks_sentmux);
1744 			send_frame = ahdlc_encode(q, state->sa_mqhead);
1745 		}
1746 
1747 		/* reset state values */
1748 		RESET_MUX_VALUES(state);
1749 	}
1750 
1751 	/* add the current frame to the queue */
1752 	if (state->sa_mqhead != NULL) {
1753 
1754 		if (state->sa_mqtail == NULL) {
1755 
1756 			/*
1757 			 * this is the first mblk in the queue create
1758 			 * a new frame to hold the PPP MUX header
1759 			 */
1760 			if ((new_frame = allocb(PPP_HDRLEN+1,
1761 			    BPRI_MED)) == NULL) {
1762 				return (send_frame);
1763 			}
1764 
1765 			if (!IS_COMP_AC(state)) {
1766 				/* add the header */
1767 				*new_frame->b_wptr++ = PPP_ALLSTATIONS;
1768 				*new_frame->b_wptr++ = PPP_UI;
1769 			}
1770 
1771 			/* do protocol compression */
1772 			if (IS_COMP_PROT(state)) {
1773 				*new_frame->b_wptr++ = PPP_MUX;
1774 			} else {
1775 				*new_frame->b_wptr++ = 0;
1776 				*new_frame->b_wptr++ = PPP_MUX;
1777 			}
1778 
1779 			*new_frame->b_wptr++ = PFF |
1780 			    (state->sa_mqlen - protolen - 1);
1781 
1782 			if (DB_REF(mp) > 1) {
1783 				tmp = copymsg(state->sa_mqhead);
1784 				freemsg(state->sa_mqhead);
1785 				if ((state->sa_mqhead = tmp) == NULL) {
1786 					return (send_frame);
1787 				}
1788 			}
1789 
1790 			if (state->sa_mqhead->b_rptr[0] == PPP_ALLSTATIONS)
1791 				state->sa_mqhead->b_rptr += 2;
1792 
1793 			linkb(new_frame, state->sa_mqhead);
1794 			state->sa_mqtail = state->sa_mqhead;
1795 			/* point mqtail to the last mblk_t */
1796 			while (state->sa_mqtail->b_cont != NULL)
1797 				state->sa_mqtail = state->sa_mqtail->b_cont;
1798 
1799 			/* change state->sa_mqhead */
1800 			state->sa_mqhead = new_frame;
1801 
1802 		}
1803 
1804 		if (state->sa_proto == proto) {
1805 
1806 			/* Check if the mblk_t is being referenced */
1807 			if (DB_REF(mp) > 1) {
1808 				tmp = copymsg(mp);
1809 				freemsg(mp);
1810 				if ((mp = tmp) == NULL) {
1811 					return (send_frame);
1812 				}
1813 			}
1814 
1815 			/*
1816 			 * match,can remove the protocol field
1817 			 * and write data there
1818 			 */
1819 			mp->b_rptr += hdrlen;
1820 			/*
1821 			 * protolen - 1 ,because the the byte with
1822 			 * the PFF bit and the length field have
1823 			 * to added
1824 			 */
1825 			mp->b_rptr += (protolen - 1);
1826 			*mp->b_rptr = (len - protolen) & 0xff;
1827 
1828 		} else {
1829 			/*
1830 			 * no match, there are three options
1831 			 * 1. write in mp
1832 			 * 2. write in mqtail
1833 			 * 3. alloc a new blk for just one byte
1834 			 */
1835 			/* Check if the mblk_t is being referenced */
1836 			if (DB_REF(mp) > 1) {
1837 				tmp = copymsg(mp);
1838 				freemsg(mp);
1839 				if ((mp = tmp) == NULL) {
1840 					return (send_frame);
1841 				}
1842 			}
1843 
1844 			if (hdrlen != 0) {
1845 
1846 				mp->b_rptr += (hdrlen-1);
1847 				*mp->b_rptr = PFF | (len);
1848 
1849 			} else if (state->sa_mqtail->b_wptr <
1850 			    DB_LIM(state->sa_mqtail)) {
1851 					*state->sa_mqtail->b_wptr++ = PFF |len;
1852 			} else {
1853 				/* allocate a new mblk & add the byte */
1854 				/* write the data */
1855 				if ((new_frame = allocb(1, BPRI_MED))
1856 				    == NULL) {
1857 					freemsg(mp);
1858 					return (send_frame);
1859 				}
1860 				*new_frame->b_wptr++ = PFF | (len);
1861 				linkb(state->sa_mqtail, new_frame);
1862 			}
1863 
1864 			/* update proto */
1865 			state->sa_proto = proto;
1866 		}
1867 
1868 		linkb(state->sa_mqtail, mp);
1869 		state->sa_mqtail = mp;
1870 		while (state->sa_mqtail->b_cont != NULL)
1871 			state->sa_mqtail = state->sa_mqtail->b_cont;
1872 		state->sa_mqlen += nlen;
1873 
1874 	} else {
1875 		state->sa_mqhead = mp;
1876 		state->sa_mqlen = len + protolen + 1;
1877 		state->sa_proto = proto;
1878 	}
1879 
1880 	if (state->sa_timeout_id == 0) {
1881 		state->sa_timeout_id = qtimeout(q, spppasyn_timer, q,
1882 		    (drv_usectohz(state->sa_timeout_usec)));
1883 	}
1884 	return (send_frame);
1885 }
1886 
1887 /*
1888  * Called from receive frame, this routine checks if it is a PPP_MUX
1889  * packet and demuxes it.  The returned pointer is a chain of mblks
1890  * using b_next and representing the demultiplexed packets.
1891  */
1892 static mblk_t *
1893 spppasyn_inpkt(queue_t *q, mblk_t *mp)
1894 {
1895 	sppp_ahdlc_t	*state = (sppp_ahdlc_t *)q->q_ptr;
1896 	ushort_t	proto;
1897 	ushort_t	prev_proto;
1898 	uint32_t	len;		/* length of subframe */
1899 	uchar_t		muxhdr;
1900 	mblk_t		*hdrmp;
1901 	mblk_t		*subframe;
1902 	mblk_t		*retmp;
1903 
1904 	if (!(mp->b_rptr[0] & PFF)) {
1905 		KINCR(pks_inmuxerrs);
1906 		(void) putnextctl1(q, M_CTL, PPPCTL_IERROR);
1907 		freemsg(mp);
1908 		return (NULL);
1909 	}
1910 
1911 	/* initialise the Last protocol and protocol length */
1912 	prev_proto = 0;
1913 
1914 	/*
1915 	 * Taking into granted that the decoded frame is contiguous
1916 	 */
1917 	retmp = NULL;
1918 	while (mp->b_rptr < mp->b_wptr) {
1919 
1920 		/*
1921 		 * get the last protocol, protocol length
1922 		 * and the length of the message
1923 		 */
1924 
1925 		/* protocol field flag and length */
1926 		muxhdr = mp->b_rptr[0];
1927 		len = muxhdr & ~PFF;
1928 
1929 		mp->b_rptr++;
1930 
1931 		/* check if there and enough bytes left in pkt */
1932 		if (MBLKL(mp) < len) {
1933 			KINCR(pks_inmuxerrs);
1934 			(void) putnextctl1(q, M_CTL, PPPCTL_IERROR);
1935 			break;
1936 		}
1937 
1938 		/* allocate memory for the header length */
1939 		if ((hdrmp = allocb(PPP_HDRLEN, BPRI_MED)) == NULL) {
1940 			KINCR(pks_inallocfails);
1941 			break;
1942 		}
1943 
1944 		/* add the ppp header to the pkt */
1945 		*hdrmp->b_wptr++ = PPP_ALLSTATIONS;
1946 		*hdrmp->b_wptr++ = PPP_UI;
1947 
1948 		/* check if the protocol field flag is set */
1949 		if (muxhdr & PFF) {
1950 
1951 			/* get the protocol */
1952 			proto = MSG_BYTE(mp, 0);
1953 			if ((proto & 1) == 0)
1954 				proto = (proto << 8) + MSG_BYTE(mp, 1);
1955 
1956 			/* reset values */
1957 			prev_proto = proto;
1958 		} else {
1959 			if (!IS_DECOMP_PROT(state))
1960 				*hdrmp->b_wptr++ = prev_proto >> 8;
1961 			*hdrmp->b_wptr++ = (prev_proto & 0xff);
1962 		}
1963 
1964 		/* get the payload from the MUXed packet */
1965 		subframe = dupmsg(mp);
1966 		subframe->b_wptr = mp->b_rptr + len;
1967 
1968 		/* link the subframe to the new frame */
1969 		linkb(hdrmp, subframe);
1970 
1971 		/* do a putnext */
1972 		retmp = sppp_mappend(retmp, hdrmp);
1973 
1974 		/* move the read pointer beyond this subframe */
1975 		mp->b_rptr += len;
1976 	}
1977 
1978 	freemsg(mp);
1979 	return (retmp);
1980 }
1981 
1982 
1983 /*
1984  * timer routine which sends out the queued pkts *
1985  */
1986 static void
1987 spppasyn_timer(void *arg)
1988 {
1989 	queue_t *q;
1990 	sppp_ahdlc_t *state;
1991 	mblk_t *mp;
1992 
1993 	ASSERT(arg);
1994 	q = (queue_t *)arg;
1995 	state = (sppp_ahdlc_t *)q->q_ptr;
1996 
1997 	if (state->sa_mqhead != NULL) {
1998 		/* increment counter */
1999 		if (state->sa_mqtail != NULL)
2000 			KINCR(pks_sentmux);
2001 		if ((mp = ahdlc_encode(q, state->sa_mqhead)) != NULL)
2002 			putnext(q, mp);
2003 		/* reset the state values over here */
2004 		RESET_MUX_VALUES(state);
2005 	}
2006 	/* clear timeout_id */
2007 	state->sa_timeout_id = 0;
2008 }
2009