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