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