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