17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * spppasyn.c - STREAMS module for doing PPP asynchronous HDLC.
37c478bd9Sstevel@tonic-gate  *
4002c70ffScarlsonj  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
57c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
6*48bbca81SDaniel Hoffman  * Copyright (c) 2016 by Delphix. All rights reserved.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * Permission to use, copy, modify, and distribute this software and its
97c478bd9Sstevel@tonic-gate  * documentation is hereby granted, provided that the above copyright
107c478bd9Sstevel@tonic-gate  * notice appears in all copies.
117c478bd9Sstevel@tonic-gate  *
127c478bd9Sstevel@tonic-gate  * SUN MAKES NO REPRESENTATION OR WARRANTIES ABOUT THE SUITABILITY OF
137c478bd9Sstevel@tonic-gate  * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
147c478bd9Sstevel@tonic-gate  * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
157c478bd9Sstevel@tonic-gate  * PARTICULAR PURPOSE, OR NON-INFRINGEMENT.  SUN SHALL NOT BE LIABLE FOR
167c478bd9Sstevel@tonic-gate  * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
177c478bd9Sstevel@tonic-gate  * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * Copyright (c) 1994 The Australian National University.
207c478bd9Sstevel@tonic-gate  * All rights reserved.
217c478bd9Sstevel@tonic-gate  *
227c478bd9Sstevel@tonic-gate  * Permission to use, copy, modify, and distribute this software and its
237c478bd9Sstevel@tonic-gate  * documentation is hereby granted, provided that the above copyright
247c478bd9Sstevel@tonic-gate  * notice appears in all copies.  This software is provided without any
257c478bd9Sstevel@tonic-gate  * warranty, express or implied. The Australian National University
267c478bd9Sstevel@tonic-gate  * makes no representations about the suitability of this software for
277c478bd9Sstevel@tonic-gate  * any purpose.
287c478bd9Sstevel@tonic-gate  *
297c478bd9Sstevel@tonic-gate  * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
307c478bd9Sstevel@tonic-gate  * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
317c478bd9Sstevel@tonic-gate  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
327c478bd9Sstevel@tonic-gate  * THE AUSTRALIAN NATIONAL UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY
337c478bd9Sstevel@tonic-gate  * OF SUCH DAMAGE.
347c478bd9Sstevel@tonic-gate  *
357c478bd9Sstevel@tonic-gate  * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
367c478bd9Sstevel@tonic-gate  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
377c478bd9Sstevel@tonic-gate  * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
387c478bd9Sstevel@tonic-gate  * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
397c478bd9Sstevel@tonic-gate  * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
407c478bd9Sstevel@tonic-gate  * OR MODIFICATIONS.
417c478bd9Sstevel@tonic-gate  *
427c478bd9Sstevel@tonic-gate  * $Id: ppp_ahdlc.c,v 1.16 2000/03/06 19:38:12 masputra Exp $
437c478bd9Sstevel@tonic-gate  */
447c478bd9Sstevel@tonic-gate 
457c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
467c478bd9Sstevel@tonic-gate 
477c478bd9Sstevel@tonic-gate #include <sys/types.h>
487c478bd9Sstevel@tonic-gate #include <sys/param.h>
497c478bd9Sstevel@tonic-gate #include <sys/stream.h>
507c478bd9Sstevel@tonic-gate #include <sys/strsun.h>
517c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
527c478bd9Sstevel@tonic-gate #include <sys/errno.h>
537c478bd9Sstevel@tonic-gate #include <sys/conf.h>
547c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
557c478bd9Sstevel@tonic-gate #include <sys/crc32.h>
567c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
577c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
587c478bd9Sstevel@tonic-gate 
597c478bd9Sstevel@tonic-gate #include <net/ppp_defs.h>
607c478bd9Sstevel@tonic-gate #include <net/pppio.h>
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate #include "s_common.h"
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate #ifdef DEBUG
657c478bd9Sstevel@tonic-gate #define	REPORT_CRC_TYPE
667c478bd9Sstevel@tonic-gate #endif
677c478bd9Sstevel@tonic-gate #include "spppasyn.h"
687c478bd9Sstevel@tonic-gate 
697c478bd9Sstevel@tonic-gate /*
707c478bd9Sstevel@tonic-gate  * This is used to tag official Solaris sources.  Please do not define
717c478bd9Sstevel@tonic-gate  * "INTERNAL_BUILD" when building this software outside of Sun
727c478bd9Sstevel@tonic-gate  * Microsystems.
737c478bd9Sstevel@tonic-gate  */
747c478bd9Sstevel@tonic-gate #ifdef INTERNAL_BUILD
757c478bd9Sstevel@tonic-gate /* MODINFO is limited to 32 characters. */
76002c70ffScarlsonj const char spppasyn_module_description[] = "PPP 4.0 AHDLC";
777c478bd9Sstevel@tonic-gate #else /* INTERNAL_BUILD */
787c478bd9Sstevel@tonic-gate const char spppasyn_module_description[] = "ANU PPP AHDLC $Revision: 1.16$";
797c478bd9Sstevel@tonic-gate 
807c478bd9Sstevel@tonic-gate /* LINTED */
817c478bd9Sstevel@tonic-gate static const char buildtime[] = "Built " __DATE__ " at " __TIME__
827c478bd9Sstevel@tonic-gate #ifdef DEBUG
837c478bd9Sstevel@tonic-gate " DEBUG"
847c478bd9Sstevel@tonic-gate #endif
857c478bd9Sstevel@tonic-gate "\n";
867c478bd9Sstevel@tonic-gate #endif /* INTERNAL_BUILD */
877c478bd9Sstevel@tonic-gate 
887c478bd9Sstevel@tonic-gate static int	spppasyn_open(queue_t *, dev_t *, int, int, cred_t *);
897c478bd9Sstevel@tonic-gate static int	spppasyn_close(queue_t *, int, cred_t *);
907c478bd9Sstevel@tonic-gate static int	spppasyn_wput(queue_t *, mblk_t *);
917c478bd9Sstevel@tonic-gate static int	spppasyn_rput(queue_t *, mblk_t *);
927c478bd9Sstevel@tonic-gate static mblk_t	*ahdlc_encode(queue_t *, mblk_t *);
937c478bd9Sstevel@tonic-gate static mblk_t	*ahdlc_decode(queue_t *, mblk_t *);
947c478bd9Sstevel@tonic-gate static void	spppasyn_timer(void *);
957c478bd9Sstevel@tonic-gate static mblk_t	*spppasyn_inpkt(queue_t *, mblk_t *);
967c478bd9Sstevel@tonic-gate static mblk_t	*spppasyn_muxencode(queue_t *, mblk_t *);
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate #define	RESET_MUX_VALUES(x)	{	\
997c478bd9Sstevel@tonic-gate 	x->sa_mqhead = x->sa_mqtail = NULL;	\
1007c478bd9Sstevel@tonic-gate 	x->sa_proto = 0;			\
1017c478bd9Sstevel@tonic-gate 	x->sa_mqlen = 0;			\
1027c478bd9Sstevel@tonic-gate }
1037c478bd9Sstevel@tonic-gate #define	IS_XMUX_ENABLED(x)	\
1047c478bd9Sstevel@tonic-gate 	((x)->sa_flags & X_MUXMASK)
1057c478bd9Sstevel@tonic-gate #define	IS_RMUX_ENABLED(x)	\
1067c478bd9Sstevel@tonic-gate 	((x)->sa_flags & R_MUXMASK)
1077c478bd9Sstevel@tonic-gate #define	IS_COMP_AC(x)	\
1087c478bd9Sstevel@tonic-gate 	((x)->sa_flags & SAF_XCOMP_AC)
1097c478bd9Sstevel@tonic-gate #define	IS_COMP_PROT(x)	\
1107c478bd9Sstevel@tonic-gate 	((x)->sa_flags & SAF_XCOMP_PROT)
1117c478bd9Sstevel@tonic-gate #define	IS_DECOMP_PROT(x)	\
1127c478bd9Sstevel@tonic-gate 	((x)->sa_flags & SAF_RDECOMP_PROT)
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate /*
1157c478bd9Sstevel@tonic-gate  * Don't send HDLC start flag if last transmit is within 1.5 seconds -
1167c478bd9Sstevel@tonic-gate  * FLAG_TIME is defined in nanoseconds.
1177c478bd9Sstevel@tonic-gate  */
1187c478bd9Sstevel@tonic-gate #define	FLAG_TIME	1500000000ul
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate /*
1217c478bd9Sstevel@tonic-gate  * The usual AHDLC implementation enables the default escaping for all
1227c478bd9Sstevel@tonic-gate  * LCP frames.  LCP_USE_DFLT() is used in this implementation to
1237c478bd9Sstevel@tonic-gate  * modify this rule slightly.  If the code number happens to be
1247c478bd9Sstevel@tonic-gate  * Echo-Request, Echo-Reply, or Discard-Request (each of which may be
1257c478bd9Sstevel@tonic-gate  * sent only when LCP is in Opened state), then one may also use the
1267c478bd9Sstevel@tonic-gate  * negotiated ACCM; the RFC is silent on this.  The theory is that
1277c478bd9Sstevel@tonic-gate  * pppd can construct Echo-Request messages that are guaranteed to
1287c478bd9Sstevel@tonic-gate  * fail if the negotiated ACCM is bad.
1297c478bd9Sstevel@tonic-gate  */
1307c478bd9Sstevel@tonic-gate #define	LCP_USE_DFLT(mp)	((code = MSG_BYTE((mp), 4)) < 9 || code > 11)
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate /*
1337c478bd9Sstevel@tonic-gate  * Extract bit c from map m, to determine if character c needs to be
1347c478bd9Sstevel@tonic-gate  * escaped.  Map 'm' is a pointer to a 256 bit map; 8 words of 32 bits
1357c478bd9Sstevel@tonic-gate  * each.
1367c478bd9Sstevel@tonic-gate  */
1377c478bd9Sstevel@tonic-gate #define	IN_TX_MAP(c, m)	\
1387c478bd9Sstevel@tonic-gate 	((m)[(c) >> 5] & (1 << ((c) & 0x1f)))
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate /*
1417c478bd9Sstevel@tonic-gate  * Checks the 32-bit receive ACCM to see if the byte should have been
1427c478bd9Sstevel@tonic-gate  * escaped by peer.
1437c478bd9Sstevel@tonic-gate  */
1447c478bd9Sstevel@tonic-gate #define	IN_RX_MAP(c, m)		(((c) < 0x20) && ((m) & (1 << (c))))
1457c478bd9Sstevel@tonic-gate 
1467c478bd9Sstevel@tonic-gate static struct module_info spppasyn_modinfo = {
1477c478bd9Sstevel@tonic-gate 	AHDLC_MOD_ID,		/* mi_idnum */
1487c478bd9Sstevel@tonic-gate 	AHDLC_MOD_NAME,		/* mi_idname */
1497c478bd9Sstevel@tonic-gate 	0,			/* mi_minpsz */
1507c478bd9Sstevel@tonic-gate 	INFPSZ,			/* mi_maxpsz */
1517c478bd9Sstevel@tonic-gate 	0,			/* mi_hiwat */
1527c478bd9Sstevel@tonic-gate 	0			/* mi_lowat */
1537c478bd9Sstevel@tonic-gate };
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate static struct qinit spppasyn_rinit = {
1567c478bd9Sstevel@tonic-gate 	spppasyn_rput,		/* qi_putp */
1577c478bd9Sstevel@tonic-gate 	NULL,			/* qi_srvp */
1587c478bd9Sstevel@tonic-gate 	spppasyn_open,		/* qi_qopen */
1597c478bd9Sstevel@tonic-gate 	spppasyn_close,		/* qi_qclose */
1607c478bd9Sstevel@tonic-gate 	NULL,			/* qi_qadmin */
1617c478bd9Sstevel@tonic-gate 	&spppasyn_modinfo,	/* qi_minfo */
1627c478bd9Sstevel@tonic-gate 	NULL			/* qi_mstat */
1637c478bd9Sstevel@tonic-gate };
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate static struct qinit spppasyn_winit = {
1667c478bd9Sstevel@tonic-gate 	spppasyn_wput,		/* qi_putp */
1677c478bd9Sstevel@tonic-gate 	NULL,			/* qi_srvp */
1687c478bd9Sstevel@tonic-gate 	NULL,			/* qi_qopen */
1697c478bd9Sstevel@tonic-gate 	NULL,			/* qi_qclose */
1707c478bd9Sstevel@tonic-gate 	NULL,			/* qi_qadmin */
1717c478bd9Sstevel@tonic-gate 	&spppasyn_modinfo,	/* qi_minfo */
1727c478bd9Sstevel@tonic-gate 	NULL			/* qi_mstat */
1737c478bd9Sstevel@tonic-gate };
1747c478bd9Sstevel@tonic-gate 
1757c478bd9Sstevel@tonic-gate struct streamtab spppasyn_tab = {
1767c478bd9Sstevel@tonic-gate 	&spppasyn_rinit,	/* st_rdinit */
1777c478bd9Sstevel@tonic-gate 	&spppasyn_winit,	/* st_wrinit */
1787c478bd9Sstevel@tonic-gate 	NULL,			/* st_muxrinit */
1797c478bd9Sstevel@tonic-gate 	NULL,			/* st_muxwinit */
1807c478bd9Sstevel@tonic-gate };
1817c478bd9Sstevel@tonic-gate 
1827c478bd9Sstevel@tonic-gate /* Matches above structure. */
1837c478bd9Sstevel@tonic-gate static const char *kstat_names[] = {
1847c478bd9Sstevel@tonic-gate 	"ioctls", "ioctlsfwd", "ioctlserr", "ctls",
1857c478bd9Sstevel@tonic-gate 	"ctlsfwd", "ctlserr", "inbadchars", "inbadcharmask",
1867c478bd9Sstevel@tonic-gate 	"inaborts", "inrunts", "inallocfails", "intoolongs",
1877c478bd9Sstevel@tonic-gate 	"outrunts", "outallocfails", "incrcerrs", "unknownwrs",
1887c478bd9Sstevel@tonic-gate 	"unknownrds", "hangups", "datain", "dataout",
1897c478bd9Sstevel@tonic-gate 	"extrabufs", "sentmux", "recvmux", "inmuxerrs",
1907c478bd9Sstevel@tonic-gate #ifdef REPORT_CRC_TYPE
1917c478bd9Sstevel@tonic-gate 	"incrctype", "outcrctype",
1927c478bd9Sstevel@tonic-gate #endif
1937c478bd9Sstevel@tonic-gate };
1947c478bd9Sstevel@tonic-gate 
1957c478bd9Sstevel@tonic-gate /* So.  This is why we have optimizing compilers. */
1967c478bd9Sstevel@tonic-gate #define	KVAL(vn)	state->sa_kstats.vn.value.ui32
1977c478bd9Sstevel@tonic-gate #define	KSET(vn, v)	KVAL(vn) = (v)
1987c478bd9Sstevel@tonic-gate #define	KADD(vn, v)	KSET(vn, KVAL(vn) + (v))
1997c478bd9Sstevel@tonic-gate #define	KOR(vn, v)	KSET(vn, KVAL(vn) | (v))
2007c478bd9Sstevel@tonic-gate #define	KINCR(vn)	KADD(vn, 1)
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate static void ppp_dump_frame(sppp_ahdlc_t *state, mblk_t *mptr,
2037c478bd9Sstevel@tonic-gate     const char *msg);
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate /*
2067c478bd9Sstevel@tonic-gate  * RCV_B7_1, etc., defined in net/pppio.h, are stored in flags also.
2077c478bd9Sstevel@tonic-gate  */
2087c478bd9Sstevel@tonic-gate #define	RCV_FLAGS	(RCV_B7_1 | RCV_B7_0 | RCV_ODDP | RCV_EVNP)
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate /*
2117c478bd9Sstevel@tonic-gate  * FCS lookup table as calculated by genfcstab.
2127c478bd9Sstevel@tonic-gate  */
2137c478bd9Sstevel@tonic-gate static ushort_t fcstab[256] = {
2147c478bd9Sstevel@tonic-gate 	0x0000,	0x1189,	0x2312,	0x329b,	0x4624,	0x57ad,	0x6536,	0x74bf,
2157c478bd9Sstevel@tonic-gate 	0x8c48,	0x9dc1,	0xaf5a,	0xbed3,	0xca6c,	0xdbe5,	0xe97e,	0xf8f7,
2167c478bd9Sstevel@tonic-gate 	0x1081,	0x0108,	0x3393,	0x221a,	0x56a5,	0x472c,	0x75b7,	0x643e,
2177c478bd9Sstevel@tonic-gate 	0x9cc9,	0x8d40,	0xbfdb,	0xae52,	0xdaed,	0xcb64,	0xf9ff,	0xe876,
2187c478bd9Sstevel@tonic-gate 	0x2102,	0x308b,	0x0210,	0x1399,	0x6726,	0x76af,	0x4434,	0x55bd,
2197c478bd9Sstevel@tonic-gate 	0xad4a,	0xbcc3,	0x8e58,	0x9fd1,	0xeb6e,	0xfae7,	0xc87c,	0xd9f5,
2207c478bd9Sstevel@tonic-gate 	0x3183,	0x200a,	0x1291,	0x0318,	0x77a7,	0x662e,	0x54b5,	0x453c,
2217c478bd9Sstevel@tonic-gate 	0xbdcb,	0xac42,	0x9ed9,	0x8f50,	0xfbef,	0xea66,	0xd8fd,	0xc974,
2227c478bd9Sstevel@tonic-gate 	0x4204,	0x538d,	0x6116,	0x709f,	0x0420,	0x15a9,	0x2732,	0x36bb,
2237c478bd9Sstevel@tonic-gate 	0xce4c,	0xdfc5,	0xed5e,	0xfcd7,	0x8868,	0x99e1,	0xab7a,	0xbaf3,
2247c478bd9Sstevel@tonic-gate 	0x5285,	0x430c,	0x7197,	0x601e,	0x14a1,	0x0528,	0x37b3,	0x263a,
2257c478bd9Sstevel@tonic-gate 	0xdecd,	0xcf44,	0xfddf,	0xec56,	0x98e9,	0x8960,	0xbbfb,	0xaa72,
2267c478bd9Sstevel@tonic-gate 	0x6306,	0x728f,	0x4014,	0x519d,	0x2522,	0x34ab,	0x0630,	0x17b9,
2277c478bd9Sstevel@tonic-gate 	0xef4e,	0xfec7,	0xcc5c,	0xddd5,	0xa96a,	0xb8e3,	0x8a78,	0x9bf1,
2287c478bd9Sstevel@tonic-gate 	0x7387,	0x620e,	0x5095,	0x411c,	0x35a3,	0x242a,	0x16b1,	0x0738,
2297c478bd9Sstevel@tonic-gate 	0xffcf,	0xee46,	0xdcdd,	0xcd54,	0xb9eb,	0xa862,	0x9af9,	0x8b70,
2307c478bd9Sstevel@tonic-gate 	0x8408,	0x9581,	0xa71a,	0xb693,	0xc22c,	0xd3a5,	0xe13e,	0xf0b7,
2317c478bd9Sstevel@tonic-gate 	0x0840,	0x19c9,	0x2b52,	0x3adb,	0x4e64,	0x5fed,	0x6d76,	0x7cff,
2327c478bd9Sstevel@tonic-gate 	0x9489,	0x8500,	0xb79b,	0xa612,	0xd2ad,	0xc324,	0xf1bf,	0xe036,
2337c478bd9Sstevel@tonic-gate 	0x18c1,	0x0948,	0x3bd3,	0x2a5a,	0x5ee5,	0x4f6c,	0x7df7,	0x6c7e,
2347c478bd9Sstevel@tonic-gate 	0xa50a,	0xb483,	0x8618,	0x9791,	0xe32e,	0xf2a7,	0xc03c,	0xd1b5,
2357c478bd9Sstevel@tonic-gate 	0x2942,	0x38cb,	0x0a50,	0x1bd9,	0x6f66,	0x7eef,	0x4c74,	0x5dfd,
2367c478bd9Sstevel@tonic-gate 	0xb58b,	0xa402,	0x9699,	0x8710,	0xf3af,	0xe226,	0xd0bd,	0xc134,
2377c478bd9Sstevel@tonic-gate 	0x39c3,	0x284a,	0x1ad1,	0x0b58,	0x7fe7,	0x6e6e,	0x5cf5,	0x4d7c,
2387c478bd9Sstevel@tonic-gate 	0xc60c,	0xd785,	0xe51e,	0xf497,	0x8028,	0x91a1,	0xa33a,	0xb2b3,
2397c478bd9Sstevel@tonic-gate 	0x4a44,	0x5bcd,	0x6956,	0x78df,	0x0c60,	0x1de9,	0x2f72,	0x3efb,
2407c478bd9Sstevel@tonic-gate 	0xd68d,	0xc704,	0xf59f,	0xe416,	0x90a9,	0x8120,	0xb3bb,	0xa232,
2417c478bd9Sstevel@tonic-gate 	0x5ac5,	0x4b4c,	0x79d7,	0x685e,	0x1ce1,	0x0d68,	0x3ff3,	0x2e7a,
2427c478bd9Sstevel@tonic-gate 	0xe70e,	0xf687,	0xc41c,	0xd595,	0xa12a,	0xb0a3,	0x8238,	0x93b1,
2437c478bd9Sstevel@tonic-gate 	0x6b46,	0x7acf,	0x4854,	0x59dd,	0x2d62,	0x3ceb,	0x0e70,	0x1ff9,
2447c478bd9Sstevel@tonic-gate 	0xf78f,	0xe606,	0xd49d,	0xc514,	0xb1ab,	0xa022,	0x92b9,	0x8330,
2457c478bd9Sstevel@tonic-gate 	0x7bc7,	0x6a4e,	0x58d5,	0x495c,	0x3de3,	0x2c6a,	0x1ef1,	0x0f78
2467c478bd9Sstevel@tonic-gate };
2477c478bd9Sstevel@tonic-gate 
2487c478bd9Sstevel@tonic-gate /*
2497c478bd9Sstevel@tonic-gate  * Per-character flags for accumulating input errors.  Flags are
2507c478bd9Sstevel@tonic-gate  * accumulated for bit 7 set to 0, bit 7 set to 1, even parity
2517c478bd9Sstevel@tonic-gate  * characters, and odd parity characters.  The link should see all
2527c478bd9Sstevel@tonic-gate  * four in the very first LCP Configure-Request if all is ok.  (C0 is
2537c478bd9Sstevel@tonic-gate  * even parity and has bit 7 set to 1, and 23 is odd parity and has
2547c478bd9Sstevel@tonic-gate  * bit 7 set to 0.)
2557c478bd9Sstevel@tonic-gate  */
2567c478bd9Sstevel@tonic-gate static uchar_t charflags[256] = {
2577c478bd9Sstevel@tonic-gate 	RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_ODDP,
2587c478bd9Sstevel@tonic-gate 	RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP,
2597c478bd9Sstevel@tonic-gate 	RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_ODDP,
2607c478bd9Sstevel@tonic-gate 	RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP,
2617c478bd9Sstevel@tonic-gate 	RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_ODDP,
2627c478bd9Sstevel@tonic-gate 	RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP,
2637c478bd9Sstevel@tonic-gate 	RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP,
2647c478bd9Sstevel@tonic-gate 	RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP,
2657c478bd9Sstevel@tonic-gate 	RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_ODDP,
2667c478bd9Sstevel@tonic-gate 	RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP,
2677c478bd9Sstevel@tonic-gate 	RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_ODDP,
2687c478bd9Sstevel@tonic-gate 	RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP,
2697c478bd9Sstevel@tonic-gate 	RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_ODDP,
2707c478bd9Sstevel@tonic-gate 	RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP,
2717c478bd9Sstevel@tonic-gate 	RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP,
2727c478bd9Sstevel@tonic-gate 	RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP,
2737c478bd9Sstevel@tonic-gate 	RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_ODDP,
2747c478bd9Sstevel@tonic-gate 	RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP,
2757c478bd9Sstevel@tonic-gate 	RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_ODDP,
2767c478bd9Sstevel@tonic-gate 	RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP,
2777c478bd9Sstevel@tonic-gate 	RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_ODDP,
2787c478bd9Sstevel@tonic-gate 	RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP,
2797c478bd9Sstevel@tonic-gate 	RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP,
2807c478bd9Sstevel@tonic-gate 	RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP,
2817c478bd9Sstevel@tonic-gate 	RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_ODDP,
2827c478bd9Sstevel@tonic-gate 	RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP,
2837c478bd9Sstevel@tonic-gate 	RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP,
2847c478bd9Sstevel@tonic-gate 	RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP,
2857c478bd9Sstevel@tonic-gate 	RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_EVNP,
2867c478bd9Sstevel@tonic-gate 	RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP,
2877c478bd9Sstevel@tonic-gate 	RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP,
2887c478bd9Sstevel@tonic-gate 	RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP,
2897c478bd9Sstevel@tonic-gate 	RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_ODDP,
2907c478bd9Sstevel@tonic-gate 	RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP,
2917c478bd9Sstevel@tonic-gate 	RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_ODDP,
2927c478bd9Sstevel@tonic-gate 	RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP,
2937c478bd9Sstevel@tonic-gate 	RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_ODDP,
2947c478bd9Sstevel@tonic-gate 	RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP,
2957c478bd9Sstevel@tonic-gate 	RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP,
2967c478bd9Sstevel@tonic-gate 	RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP,
2977c478bd9Sstevel@tonic-gate 	RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_ODDP,
2987c478bd9Sstevel@tonic-gate 	RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP,
2997c478bd9Sstevel@tonic-gate 	RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_1|RCV_ODDP,
3007c478bd9Sstevel@tonic-gate 	RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP,
3017c478bd9Sstevel@tonic-gate 	RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_ODDP,
3027c478bd9Sstevel@tonic-gate 	RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP,
3037c478bd9Sstevel@tonic-gate 	RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP,
3047c478bd9Sstevel@tonic-gate 	RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP,
3057c478bd9Sstevel@tonic-gate 	RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_ODDP,
3067c478bd9Sstevel@tonic-gate 	RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_EVNP,
3077c478bd9Sstevel@tonic-gate 	RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_ODDP,
3087c478bd9Sstevel@tonic-gate 	RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP,
3097c478bd9Sstevel@tonic-gate 	RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_ODDP,
3107c478bd9Sstevel@tonic-gate 	RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP,
3117c478bd9Sstevel@tonic-gate 	RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP,
3127c478bd9Sstevel@tonic-gate 	RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP,
3137c478bd9Sstevel@tonic-gate 	RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_EVNP,
3147c478bd9Sstevel@tonic-gate 	RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP,
3157c478bd9Sstevel@tonic-gate 	RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP,
3167c478bd9Sstevel@tonic-gate 	RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP,
3177c478bd9Sstevel@tonic-gate 	RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_ODDP,
3187c478bd9Sstevel@tonic-gate 	RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP,
3197c478bd9Sstevel@tonic-gate 	RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP,
3207c478bd9Sstevel@tonic-gate 	RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP,
3217c478bd9Sstevel@tonic-gate 	RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_ODDP,
3227c478bd9Sstevel@tonic-gate 	RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_EVNP,
3237c478bd9Sstevel@tonic-gate 	RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_ODDP,
3247c478bd9Sstevel@tonic-gate 	RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP,
3257c478bd9Sstevel@tonic-gate 	RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_ODDP,
3267c478bd9Sstevel@tonic-gate 	RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_EVNP,
3277c478bd9Sstevel@tonic-gate 	RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_EVNP,
3287c478bd9Sstevel@tonic-gate 	RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_EVNP,
3297c478bd9Sstevel@tonic-gate 	RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_ODDP,
3307c478bd9Sstevel@tonic-gate 	RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_EVNP,
3317c478bd9Sstevel@tonic-gate 	RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_ODDP,
3327c478bd9Sstevel@tonic-gate 	RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP,
3337c478bd9Sstevel@tonic-gate 	RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_ODDP,
3347c478bd9Sstevel@tonic-gate 	RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP,
3357c478bd9Sstevel@tonic-gate 	RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP,
3367c478bd9Sstevel@tonic-gate 	RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP,
3377c478bd9Sstevel@tonic-gate 	RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_ODDP,
3387c478bd9Sstevel@tonic-gate 	RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_EVNP,
3397c478bd9Sstevel@tonic-gate 	RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_ODDP,
3407c478bd9Sstevel@tonic-gate 	RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP,
3417c478bd9Sstevel@tonic-gate 	RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_ODDP,
3427c478bd9Sstevel@tonic-gate 	RCV_B7_1|RCV_EVNP
3437c478bd9Sstevel@tonic-gate };
3447c478bd9Sstevel@tonic-gate 
3457c478bd9Sstevel@tonic-gate /*
3467c478bd9Sstevel@tonic-gate  * Append two lists; preserve message boundaries.
3477c478bd9Sstevel@tonic-gate  * Warning: uses b_next.
3487c478bd9Sstevel@tonic-gate  */
3497c478bd9Sstevel@tonic-gate static mblk_t *
sppp_mappend(mblk_t * m1,mblk_t * m2)3507c478bd9Sstevel@tonic-gate sppp_mappend(mblk_t *m1, mblk_t *m2)
3517c478bd9Sstevel@tonic-gate {
3527c478bd9Sstevel@tonic-gate 	mblk_t *mret;
3537c478bd9Sstevel@tonic-gate 
3547c478bd9Sstevel@tonic-gate 	if (m1 == NULL)
3557c478bd9Sstevel@tonic-gate 		return (m2);
3567c478bd9Sstevel@tonic-gate 	if (m2 == NULL)
3577c478bd9Sstevel@tonic-gate 		return (m1);
3587c478bd9Sstevel@tonic-gate 
3597c478bd9Sstevel@tonic-gate 	mret = m1;
3607c478bd9Sstevel@tonic-gate 	while (m1->b_next != NULL)
3617c478bd9Sstevel@tonic-gate 		m1 = m1->b_next;
3627c478bd9Sstevel@tonic-gate 	m1->b_next = m2;
3637c478bd9Sstevel@tonic-gate 	return (mret);
3647c478bd9Sstevel@tonic-gate }
3657c478bd9Sstevel@tonic-gate 
3667c478bd9Sstevel@tonic-gate /*
3677c478bd9Sstevel@tonic-gate  * Concatenate two mblk lists.
3687c478bd9Sstevel@tonic-gate  */
3697c478bd9Sstevel@tonic-gate static mblk_t *
sppp_mcat(mblk_t * m1,mblk_t * m2)3707c478bd9Sstevel@tonic-gate sppp_mcat(mblk_t *m1, mblk_t *m2)
3717c478bd9Sstevel@tonic-gate {
3727c478bd9Sstevel@tonic-gate 	mblk_t *mret;
3737c478bd9Sstevel@tonic-gate 
3747c478bd9Sstevel@tonic-gate 	if (m1 == NULL)
3757c478bd9Sstevel@tonic-gate 		return (m2);
3767c478bd9Sstevel@tonic-gate 	if (m2 == NULL)
3777c478bd9Sstevel@tonic-gate 		return (m1);
3787c478bd9Sstevel@tonic-gate 
3797c478bd9Sstevel@tonic-gate 	mret = m1;
3807c478bd9Sstevel@tonic-gate 	while (m1->b_cont != NULL)
3817c478bd9Sstevel@tonic-gate 		m1 = m1->b_cont;
3827c478bd9Sstevel@tonic-gate 	m1->b_cont = m2;
3837c478bd9Sstevel@tonic-gate 	return (mret);
3847c478bd9Sstevel@tonic-gate }
3857c478bd9Sstevel@tonic-gate 
3867c478bd9Sstevel@tonic-gate /*
3877c478bd9Sstevel@tonic-gate  * spppasyn_open()
3887c478bd9Sstevel@tonic-gate  *
3897c478bd9Sstevel@tonic-gate  * STREAMS module open (entry) point.  Called when spppasyn is pushed
3907c478bd9Sstevel@tonic-gate  * onto an asynchronous serial stream.
3917c478bd9Sstevel@tonic-gate  */
3927c478bd9Sstevel@tonic-gate /* ARGSUSED */
3937c478bd9Sstevel@tonic-gate static int
spppasyn_open(queue_t * q,dev_t * devp,int flag,int sflag,cred_t * credp)3947c478bd9Sstevel@tonic-gate spppasyn_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp)
3957c478bd9Sstevel@tonic-gate {
3967c478bd9Sstevel@tonic-gate 	sppp_ahdlc_t	*state;
3977c478bd9Sstevel@tonic-gate 
3987c478bd9Sstevel@tonic-gate 	ASSERT(q != NULL);
3997c478bd9Sstevel@tonic-gate 
4007c478bd9Sstevel@tonic-gate 	if (q->q_ptr != NULL) {
4017c478bd9Sstevel@tonic-gate 		return (0);		/* return if already opened */
4027c478bd9Sstevel@tonic-gate 	}
4037c478bd9Sstevel@tonic-gate 
4047c478bd9Sstevel@tonic-gate 	if (sflag != MODOPEN) {
4057c478bd9Sstevel@tonic-gate 		return (EINVAL);	/* only open as a module */
4067c478bd9Sstevel@tonic-gate 	}
4077c478bd9Sstevel@tonic-gate 
4087c478bd9Sstevel@tonic-gate 	state = (sppp_ahdlc_t *)kmem_zalloc(sizeof (sppp_ahdlc_t), KM_SLEEP);
4097c478bd9Sstevel@tonic-gate 	ASSERT(state != NULL);
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate 	q->q_ptr = (caddr_t)state;
4127c478bd9Sstevel@tonic-gate 	WR(q)->q_ptr = (caddr_t)state;
4137c478bd9Sstevel@tonic-gate 
4147c478bd9Sstevel@tonic-gate 	state->sa_xaccm[0] = 0xffffffff;	/* escape 0x00 through 0x1f */
4157c478bd9Sstevel@tonic-gate 	state->sa_xaccm[3] = 0x60000000;   /* escape 0x7d and 0x7e */
4167c478bd9Sstevel@tonic-gate 	state->sa_mru = PPP_MRU;		/* default of 1500 bytes */
4177c478bd9Sstevel@tonic-gate 
4187c478bd9Sstevel@tonic-gate 	qprocson(q);
4197c478bd9Sstevel@tonic-gate 
4207c478bd9Sstevel@tonic-gate 	return (0);
4217c478bd9Sstevel@tonic-gate }
4227c478bd9Sstevel@tonic-gate 
4237c478bd9Sstevel@tonic-gate /*
4247c478bd9Sstevel@tonic-gate  * spppasyn_close()
4257c478bd9Sstevel@tonic-gate  *
4267c478bd9Sstevel@tonic-gate  * STREAMS module close (exit) point
4277c478bd9Sstevel@tonic-gate  */
4287c478bd9Sstevel@tonic-gate /* ARGSUSED */
4297c478bd9Sstevel@tonic-gate static int
spppasyn_close(queue_t * q,int flag,cred_t * credp)4307c478bd9Sstevel@tonic-gate spppasyn_close(queue_t *q, int flag, cred_t *credp)
4317c478bd9Sstevel@tonic-gate {
4327c478bd9Sstevel@tonic-gate 	sppp_ahdlc_t	*state;
4337c478bd9Sstevel@tonic-gate 
4347c478bd9Sstevel@tonic-gate 	ASSERT(q != NULL);
4357c478bd9Sstevel@tonic-gate 	state = (sppp_ahdlc_t *)q->q_ptr;
4367c478bd9Sstevel@tonic-gate 	ASSERT(state != NULL);
4377c478bd9Sstevel@tonic-gate 
4387c478bd9Sstevel@tonic-gate 	/* We're leaving now.  No more calls, please. */
4397c478bd9Sstevel@tonic-gate 	qprocsoff(q);
4407c478bd9Sstevel@tonic-gate 
4417c478bd9Sstevel@tonic-gate 	if (state->sa_rx_buf != NULL) {
4427c478bd9Sstevel@tonic-gate 		freemsg(state->sa_rx_buf);
4437c478bd9Sstevel@tonic-gate 		state->sa_rx_buf = NULL;
4447c478bd9Sstevel@tonic-gate 	}
4457c478bd9Sstevel@tonic-gate 
4467c478bd9Sstevel@tonic-gate 	if (state->sa_ksp != NULL) {
4477c478bd9Sstevel@tonic-gate 		kstat_delete(state->sa_ksp);
4487c478bd9Sstevel@tonic-gate 		state->sa_ksp = NULL;
4497c478bd9Sstevel@tonic-gate 	}
4507c478bd9Sstevel@tonic-gate 
4517c478bd9Sstevel@tonic-gate 	if (state->sa_mqhead != NULL)
4527c478bd9Sstevel@tonic-gate 		freemsg(state->sa_mqhead);
4537c478bd9Sstevel@tonic-gate 	/* remove the time out routine */
4547c478bd9Sstevel@tonic-gate 	if (state->sa_timeout_id != 0)
4557c478bd9Sstevel@tonic-gate 		(void) quntimeout(q, state->sa_timeout_id);
4567c478bd9Sstevel@tonic-gate 
4577c478bd9Sstevel@tonic-gate 	q->q_ptr = NULL;
4587c478bd9Sstevel@tonic-gate 	WR(q)->q_ptr = NULL;
4597c478bd9Sstevel@tonic-gate 	kmem_free(state, sizeof (sppp_ahdlc_t));
4607c478bd9Sstevel@tonic-gate 
4617c478bd9Sstevel@tonic-gate 	return (0);
4627c478bd9Sstevel@tonic-gate }
4637c478bd9Sstevel@tonic-gate 
4647c478bd9Sstevel@tonic-gate /*
4657c478bd9Sstevel@tonic-gate  * Create the standard kernel statistics structure and attach it to
4667c478bd9Sstevel@tonic-gate  * the current state structure.  This can be called only after
4677c478bd9Sstevel@tonic-gate  * assigning the unit number.
4687c478bd9Sstevel@tonic-gate  */
4697c478bd9Sstevel@tonic-gate static void
create_kstats(sppp_ahdlc_t * state)4707c478bd9Sstevel@tonic-gate create_kstats(sppp_ahdlc_t *state)
4717c478bd9Sstevel@tonic-gate {
4727c478bd9Sstevel@tonic-gate 	kstat_t *ksp;
4737c478bd9Sstevel@tonic-gate 	char unitname[KSTAT_STRLEN];
4747c478bd9Sstevel@tonic-gate 	int nstat, i;
4757c478bd9Sstevel@tonic-gate 	kstat_named_t *knt;
4767c478bd9Sstevel@tonic-gate 
4777c478bd9Sstevel@tonic-gate 	nstat = sizeof (state->sa_kstats) / sizeof (kstat_named_t);
4787c478bd9Sstevel@tonic-gate 	knt = (kstat_named_t *)&state->sa_kstats;
4797c478bd9Sstevel@tonic-gate 	for (i = 0; i < nstat; i++, knt++) {
4807c478bd9Sstevel@tonic-gate #ifdef DEBUG
4817c478bd9Sstevel@tonic-gate 		/* Just in case I do something silly here. */
4827c478bd9Sstevel@tonic-gate 		if (i >= sizeof (kstat_names) / sizeof (kstat_names[0]))
4837c478bd9Sstevel@tonic-gate 			(void) sprintf(knt->name, "unknown%d", i);
4847c478bd9Sstevel@tonic-gate 		else
4857c478bd9Sstevel@tonic-gate #endif
4867c478bd9Sstevel@tonic-gate 			(void) strncpy(knt->name, kstat_names[i],
4877c478bd9Sstevel@tonic-gate 			    sizeof (knt->name));
4887c478bd9Sstevel@tonic-gate 		knt->data_type = KSTAT_DATA_UINT32;
4897c478bd9Sstevel@tonic-gate 	}
4907c478bd9Sstevel@tonic-gate 	/*
4917c478bd9Sstevel@tonic-gate 	 * sprintf is known to be safe here because KSTAT_STRLEN is
4927c478bd9Sstevel@tonic-gate 	 * 31, the maximum module name length is 8, and the maximum
4937c478bd9Sstevel@tonic-gate 	 * string length from %d is 11.  This was once snprintf, but
4947c478bd9Sstevel@tonic-gate 	 * that's not backward-compatible with Solaris 2.6.
4957c478bd9Sstevel@tonic-gate 	 */
496002c70ffScarlsonj 	(void) sprintf(unitname, "%s" "%d", AHDLC_MOD_NAME, state->sa_unit);
4977c478bd9Sstevel@tonic-gate 	ksp = kstat_create(AHDLC_MOD_NAME, state->sa_unit, unitname, "net",
4987c478bd9Sstevel@tonic-gate 	    KSTAT_TYPE_NAMED, nstat, KSTAT_FLAG_VIRTUAL);
4997c478bd9Sstevel@tonic-gate 	if (ksp != NULL) {
5007c478bd9Sstevel@tonic-gate 		ksp->ks_data = (void *)&state->sa_kstats;
5017c478bd9Sstevel@tonic-gate 		kstat_install(ksp);
5027c478bd9Sstevel@tonic-gate 	}
5037c478bd9Sstevel@tonic-gate 	state->sa_ksp = ksp;
5047c478bd9Sstevel@tonic-gate #ifdef REPORT_CRC_TYPE
5057c478bd9Sstevel@tonic-gate 	KSET(pks_outcrctype, 16);
5067c478bd9Sstevel@tonic-gate 	KSET(pks_incrctype, 16);
5077c478bd9Sstevel@tonic-gate #endif
5087c478bd9Sstevel@tonic-gate }
5097c478bd9Sstevel@tonic-gate 
5107c478bd9Sstevel@tonic-gate /*
5117c478bd9Sstevel@tonic-gate  * spppasyn_inner_ioctl
5127c478bd9Sstevel@tonic-gate  *
5137c478bd9Sstevel@tonic-gate  * MT-Perimeters:
5147c478bd9Sstevel@tonic-gate  *	exclusive inner
5157c478bd9Sstevel@tonic-gate  *
5167c478bd9Sstevel@tonic-gate  * Handle state-affecting ioctls.
5177c478bd9Sstevel@tonic-gate  */
5187c478bd9Sstevel@tonic-gate static void
spppasyn_inner_ioctl(queue_t * q,mblk_t * mp)5197c478bd9Sstevel@tonic-gate spppasyn_inner_ioctl(queue_t *q, mblk_t *mp)
5207c478bd9Sstevel@tonic-gate {
5217c478bd9Sstevel@tonic-gate 	sppp_ahdlc_t		*state;
5227c478bd9Sstevel@tonic-gate 	struct iocblk		*iop;
5237c478bd9Sstevel@tonic-gate 	int			error;
5247c478bd9Sstevel@tonic-gate 	int			flagval;
5257c478bd9Sstevel@tonic-gate 	int			len;
5267c478bd9Sstevel@tonic-gate 	uint32_t		mux_flags;
5277c478bd9Sstevel@tonic-gate 	uint32_t		mask;
5287c478bd9Sstevel@tonic-gate 	int			flagmask;
5297c478bd9Sstevel@tonic-gate 
5307c478bd9Sstevel@tonic-gate 	ASSERT(q != NULL && mp != NULL);
5317c478bd9Sstevel@tonic-gate 	state = (sppp_ahdlc_t *)q->q_ptr;
5327c478bd9Sstevel@tonic-gate 	iop = (struct iocblk *)mp->b_rptr;
5337c478bd9Sstevel@tonic-gate 	ASSERT(state != NULL && iop != NULL);
5347c478bd9Sstevel@tonic-gate 
5357c478bd9Sstevel@tonic-gate 	error = EINVAL;
5367c478bd9Sstevel@tonic-gate 	len = 0;
5377c478bd9Sstevel@tonic-gate 
5387c478bd9Sstevel@tonic-gate 	switch (iop->ioc_cmd) {
5397c478bd9Sstevel@tonic-gate 	case PPPIO_XFCS:
5407c478bd9Sstevel@tonic-gate 		/* Check for valid option length */
5417c478bd9Sstevel@tonic-gate 		if (iop->ioc_count != sizeof (uint32_t) || mp->b_cont == NULL)
5427c478bd9Sstevel@tonic-gate 			break;
5437c478bd9Sstevel@tonic-gate 
5447c478bd9Sstevel@tonic-gate 		/* Grab flag value */
5457c478bd9Sstevel@tonic-gate 		flagval = *(uint32_t *)mp->b_cont->b_rptr;
5467c478bd9Sstevel@tonic-gate 		if (flagval < PPPFCS_16 || flagval > PPPFCS_NONE)
5477c478bd9Sstevel@tonic-gate 			break;
5487c478bd9Sstevel@tonic-gate 		state->sa_flags &= ~SAF_XMITCRC32 & ~SAF_XMITCRCNONE;
5497c478bd9Sstevel@tonic-gate 		if (flagval == PPPFCS_32) {
5507c478bd9Sstevel@tonic-gate #ifdef REPORT_CRC_TYPE
5517c478bd9Sstevel@tonic-gate 			KSET(pks_outcrctype, 32);
5527c478bd9Sstevel@tonic-gate #endif
5537c478bd9Sstevel@tonic-gate 			state->sa_flags |= SAF_XMITCRC32;
5547c478bd9Sstevel@tonic-gate 		} else if (flagval == PPPFCS_NONE) {
5557c478bd9Sstevel@tonic-gate #ifdef REPORT_CRC_TYPE
5567c478bd9Sstevel@tonic-gate 			KSET(pks_outcrctype, 0);
5577c478bd9Sstevel@tonic-gate #endif
5587c478bd9Sstevel@tonic-gate 			state->sa_flags |= SAF_XMITCRCNONE;
5597c478bd9Sstevel@tonic-gate 		}
5607c478bd9Sstevel@tonic-gate #ifdef REPORT_CRC_TYPE
5617c478bd9Sstevel@tonic-gate 		else {
5627c478bd9Sstevel@tonic-gate 			KSET(pks_outcrctype, 16);
5637c478bd9Sstevel@tonic-gate 		}
5647c478bd9Sstevel@tonic-gate #endif
5657c478bd9Sstevel@tonic-gate 
5667c478bd9Sstevel@tonic-gate 		/* Return success */
5677c478bd9Sstevel@tonic-gate 		error = 0;
5687c478bd9Sstevel@tonic-gate 		break;
5697c478bd9Sstevel@tonic-gate 
5707c478bd9Sstevel@tonic-gate 	case PPPIO_RFCS:
5717c478bd9Sstevel@tonic-gate 		/* Check for valid option length */
5727c478bd9Sstevel@tonic-gate 		if (iop->ioc_count != sizeof (uint32_t) || mp->b_cont == NULL)
5737c478bd9Sstevel@tonic-gate 			break;
5747c478bd9Sstevel@tonic-gate 
5757c478bd9Sstevel@tonic-gate 		/* Grab flag value */
5767c478bd9Sstevel@tonic-gate 		flagval = *(uint32_t *)mp->b_cont->b_rptr;
5777c478bd9Sstevel@tonic-gate 		if (flagval < PPPFCS_16 || flagval > PPPFCS_NONE)
5787c478bd9Sstevel@tonic-gate 			break;
5797c478bd9Sstevel@tonic-gate 		state->sa_flags &= ~SAF_RECVCRC32 & ~SAF_RECVCRCNONE;
5807c478bd9Sstevel@tonic-gate 		if (flagval == PPPFCS_32) {
5817c478bd9Sstevel@tonic-gate #ifdef REPORT_CRC_TYPE
5827c478bd9Sstevel@tonic-gate 			KSET(pks_incrctype, 32);
5837c478bd9Sstevel@tonic-gate #endif
5847c478bd9Sstevel@tonic-gate 			state->sa_flags |= SAF_RECVCRC32;
5857c478bd9Sstevel@tonic-gate 		} else if (flagval == PPPFCS_NONE) {
5867c478bd9Sstevel@tonic-gate #ifdef REPORT_CRC_TYPE
5877c478bd9Sstevel@tonic-gate 			KSET(pks_incrctype, 0);
5887c478bd9Sstevel@tonic-gate #endif
5897c478bd9Sstevel@tonic-gate 			state->sa_flags |= SAF_RECVCRCNONE;
5907c478bd9Sstevel@tonic-gate 		}
5917c478bd9Sstevel@tonic-gate #ifdef REPORT_CRC_TYPE
5927c478bd9Sstevel@tonic-gate 		else {
5937c478bd9Sstevel@tonic-gate 			KSET(pks_incrctype, 16);
5947c478bd9Sstevel@tonic-gate 		}
5957c478bd9Sstevel@tonic-gate #endif
5967c478bd9Sstevel@tonic-gate 
5977c478bd9Sstevel@tonic-gate 		/* Return success */
5987c478bd9Sstevel@tonic-gate 		error = 0;
5997c478bd9Sstevel@tonic-gate 		break;
6007c478bd9Sstevel@tonic-gate 
6017c478bd9Sstevel@tonic-gate 	case PPPIO_XACCM:
6027c478bd9Sstevel@tonic-gate 		/* Check for valid asyncmap length */
6037c478bd9Sstevel@tonic-gate 		if (iop->ioc_count < sizeof (uint32_t) ||
6047c478bd9Sstevel@tonic-gate 		    iop->ioc_count > sizeof (ext_accm) ||
6057c478bd9Sstevel@tonic-gate 		    mp->b_cont == NULL)
6067c478bd9Sstevel@tonic-gate 			break;
6077c478bd9Sstevel@tonic-gate 
6087c478bd9Sstevel@tonic-gate 		/* Copy user's asyncmap into our state structure. */
6097c478bd9Sstevel@tonic-gate 		bcopy((caddr_t)mp->b_cont->b_rptr,
6107c478bd9Sstevel@tonic-gate 		    (caddr_t)state->sa_xaccm, iop->ioc_count);
6117c478bd9Sstevel@tonic-gate 
6127c478bd9Sstevel@tonic-gate 		state->sa_xaccm[2] &= ~0x40000000;	/* don't escape 0x5e */
6137c478bd9Sstevel@tonic-gate 		state->sa_xaccm[3] |= 0x60000000;	/* escape 0x7d, 0x7e */
6147c478bd9Sstevel@tonic-gate 
6157c478bd9Sstevel@tonic-gate 		error = 0;
6167c478bd9Sstevel@tonic-gate 		break;
6177c478bd9Sstevel@tonic-gate 
6187c478bd9Sstevel@tonic-gate 	case PPPIO_RACCM:
6197c478bd9Sstevel@tonic-gate 		/* Check for valid asyncmap length (only ctrl chars) */
6207c478bd9Sstevel@tonic-gate 		if (iop->ioc_count != sizeof (uint32_t) ||
6217c478bd9Sstevel@tonic-gate 		    mp->b_cont == NULL)
6227c478bd9Sstevel@tonic-gate 			break;
6237c478bd9Sstevel@tonic-gate 
6247c478bd9Sstevel@tonic-gate 		state->sa_raccm = *(uint32_t *)mp->b_cont->b_rptr;
6257c478bd9Sstevel@tonic-gate 
6267c478bd9Sstevel@tonic-gate 		error = 0;
6277c478bd9Sstevel@tonic-gate 		break;
6287c478bd9Sstevel@tonic-gate 
6297c478bd9Sstevel@tonic-gate 	case PPPIO_LASTMOD:
6307c478bd9Sstevel@tonic-gate 		/* We already know this. */
6317c478bd9Sstevel@tonic-gate 		state->sa_flags |= SAF_LASTMOD;
6327c478bd9Sstevel@tonic-gate 		error = 0;
6337c478bd9Sstevel@tonic-gate 		break;
6347c478bd9Sstevel@tonic-gate 
6357c478bd9Sstevel@tonic-gate 	case PPPIO_MUX:
6367c478bd9Sstevel@tonic-gate 		/* set the compression flags */
6377c478bd9Sstevel@tonic-gate 		if (iop->ioc_count != 2 * sizeof (uint32_t) ||
6387c478bd9Sstevel@tonic-gate 		    mp->b_cont == NULL)
6397c478bd9Sstevel@tonic-gate 			break;
6407c478bd9Sstevel@tonic-gate 
6417c478bd9Sstevel@tonic-gate 		/* set the mux flags */
6427c478bd9Sstevel@tonic-gate 		mux_flags = ((uint32_t *)mp->b_cont->b_rptr)[0];
6437c478bd9Sstevel@tonic-gate 		mask = ((uint32_t *)mp->b_cont->b_rptr)[1];
6447c478bd9Sstevel@tonic-gate 		if (mux_flags != 0)
6457c478bd9Sstevel@tonic-gate 			state->sa_flags = (state->sa_flags & ~mask) | (mask);
6467c478bd9Sstevel@tonic-gate 
6477c478bd9Sstevel@tonic-gate 		/* set the multiplexing timer value */
6487c478bd9Sstevel@tonic-gate 		if (mask & R_MUXMASK)
6497c478bd9Sstevel@tonic-gate 			state->sa_timeout_usec = mux_flags;
6507c478bd9Sstevel@tonic-gate 
6517c478bd9Sstevel@tonic-gate 		error = 0;
6527c478bd9Sstevel@tonic-gate 		break;
6537c478bd9Sstevel@tonic-gate 
6547c478bd9Sstevel@tonic-gate 	case PPPIO_CFLAGS:
6557c478bd9Sstevel@tonic-gate 		if (iop->ioc_count != 2 * sizeof (uint32_t) ||
6567c478bd9Sstevel@tonic-gate 		    mp->b_cont == NULL)
6577c478bd9Sstevel@tonic-gate 			break;
6587c478bd9Sstevel@tonic-gate 
6597c478bd9Sstevel@tonic-gate 		flagval = (((uint32_t *)mp->b_cont->b_rptr)[0] << 20) &
6607c478bd9Sstevel@tonic-gate 		    (SAF_RDECOMP_PROT | SAF_RDECOMP_AC | SAF_XCOMP_PROT |
661002c70ffScarlsonj 		    SAF_XCOMP_AC);
6627c478bd9Sstevel@tonic-gate 		flagmask = (((uint32_t *)mp->b_cont->b_rptr)[1] << 20) &
6637c478bd9Sstevel@tonic-gate 		    (SAF_RDECOMP_PROT | SAF_RDECOMP_AC | SAF_XCOMP_PROT |
664002c70ffScarlsonj 		    SAF_XCOMP_AC);
6657c478bd9Sstevel@tonic-gate 		state->sa_flags = flagval | (state->sa_flags & ~flagmask);
6667c478bd9Sstevel@tonic-gate 		*(uint32_t *)mp->b_cont->b_rptr = state->sa_flags >> 20;
6677c478bd9Sstevel@tonic-gate 		len = sizeof (uint32_t);
6687c478bd9Sstevel@tonic-gate 		error = 0;
6697c478bd9Sstevel@tonic-gate 		break;
6707c478bd9Sstevel@tonic-gate 
6717c478bd9Sstevel@tonic-gate 	case PPPIO_DEBUG:
6727c478bd9Sstevel@tonic-gate 		if (iop->ioc_count != sizeof (uint32_t) || mp->b_cont == NULL)
6737c478bd9Sstevel@tonic-gate 			break;
6747c478bd9Sstevel@tonic-gate 
6757c478bd9Sstevel@tonic-gate 		flagval = *(uint32_t *)mp->b_cont->b_rptr;
6767c478bd9Sstevel@tonic-gate 		if (flagval != PPPDBG_LOG + PPPDBG_AHDLC) {
6777c478bd9Sstevel@tonic-gate 			putnext(q, mp);
6787c478bd9Sstevel@tonic-gate 			return;
6797c478bd9Sstevel@tonic-gate 		}
6807c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, AHDLC_MOD_NAME "%d: debug log enabled\n",
6817c478bd9Sstevel@tonic-gate 		    state->sa_unit);
6827c478bd9Sstevel@tonic-gate 		state->sa_flags |= SAF_XMITDUMP | SAF_RECVDUMP;
6837c478bd9Sstevel@tonic-gate 		error = 0;
6847c478bd9Sstevel@tonic-gate 		break;
6857c478bd9Sstevel@tonic-gate 	}
6867c478bd9Sstevel@tonic-gate 
6877c478bd9Sstevel@tonic-gate 	if (error == 0) {
6887c478bd9Sstevel@tonic-gate 		/* Success; tell the user */
6897c478bd9Sstevel@tonic-gate 		if (mp->b_cont == NULL)
6907c478bd9Sstevel@tonic-gate 			len = 0;
6917c478bd9Sstevel@tonic-gate 		else
6927c478bd9Sstevel@tonic-gate 			mp->b_cont->b_wptr = mp->b_cont->b_rptr + len;
6937c478bd9Sstevel@tonic-gate 		miocack(q, mp, len, 0);
6947c478bd9Sstevel@tonic-gate 	} else {
6957c478bd9Sstevel@tonic-gate 		/* Failure; send error back upstream. */
6967c478bd9Sstevel@tonic-gate 		KINCR(pks_ioctlserr);
6977c478bd9Sstevel@tonic-gate 		miocnak(q, mp, 0, error);
6987c478bd9Sstevel@tonic-gate 	}
6997c478bd9Sstevel@tonic-gate }
7007c478bd9Sstevel@tonic-gate 
7017c478bd9Sstevel@tonic-gate /*
7027c478bd9Sstevel@tonic-gate  * spppasyn_inner_mctl
7037c478bd9Sstevel@tonic-gate  *
7047c478bd9Sstevel@tonic-gate  * MT-Perimeters:
7057c478bd9Sstevel@tonic-gate  *	exclusive inner
7067c478bd9Sstevel@tonic-gate  *
7077c478bd9Sstevel@tonic-gate  * Handle state-affecting M_CTL messages.
7087c478bd9Sstevel@tonic-gate  */
7097c478bd9Sstevel@tonic-gate static void
spppasyn_inner_mctl(queue_t * q,mblk_t * mp)7107c478bd9Sstevel@tonic-gate spppasyn_inner_mctl(queue_t *q, mblk_t *mp)
7117c478bd9Sstevel@tonic-gate {
7127c478bd9Sstevel@tonic-gate 	sppp_ahdlc_t	*state;
7137c478bd9Sstevel@tonic-gate 	int		msglen;
7147c478bd9Sstevel@tonic-gate 	int		error;
7157c478bd9Sstevel@tonic-gate 
7167c478bd9Sstevel@tonic-gate 	ASSERT(q != NULL && mp != NULL);
7177c478bd9Sstevel@tonic-gate 	state = (sppp_ahdlc_t *)q->q_ptr;
7187c478bd9Sstevel@tonic-gate 	ASSERT(state != NULL);
7197c478bd9Sstevel@tonic-gate 
7207c478bd9Sstevel@tonic-gate 	msglen = MBLKL(mp);
7217c478bd9Sstevel@tonic-gate 	error = 0;
7227c478bd9Sstevel@tonic-gate 	switch (*mp->b_rptr) {
7237c478bd9Sstevel@tonic-gate 	case PPPCTL_MTU:
7247c478bd9Sstevel@tonic-gate 				/* Just ignore the MTU */
7257c478bd9Sstevel@tonic-gate 		break;
7267c478bd9Sstevel@tonic-gate 
7277c478bd9Sstevel@tonic-gate 	case PPPCTL_MRU:
7287c478bd9Sstevel@tonic-gate 		if (msglen != 4)
7297c478bd9Sstevel@tonic-gate 			error = EINVAL;
7307c478bd9Sstevel@tonic-gate 		else
7317c478bd9Sstevel@tonic-gate 			state->sa_mru =
7327c478bd9Sstevel@tonic-gate 			    ((ushort_t *)mp->b_rptr)[1];
7337c478bd9Sstevel@tonic-gate 		break;
7347c478bd9Sstevel@tonic-gate 
7357c478bd9Sstevel@tonic-gate 	case PPPCTL_UNIT:
7367c478bd9Sstevel@tonic-gate 		if (state->sa_ksp != NULL) {
7377c478bd9Sstevel@tonic-gate 			error = EINVAL;
7387c478bd9Sstevel@tonic-gate 			break;
7397c478bd9Sstevel@tonic-gate 		}
7407c478bd9Sstevel@tonic-gate 		if (msglen == 2)
7417c478bd9Sstevel@tonic-gate 			state->sa_unit = mp->b_rptr[1];
7427c478bd9Sstevel@tonic-gate 		else if (msglen == 8)
7437c478bd9Sstevel@tonic-gate 			state->sa_unit =
7447c478bd9Sstevel@tonic-gate 			    ((uint32_t *)mp->b_rptr)[1];
7457c478bd9Sstevel@tonic-gate 		else
7467c478bd9Sstevel@tonic-gate 			error = EINVAL;
7477c478bd9Sstevel@tonic-gate 		if (error == 0 && state->sa_ksp == NULL)
7487c478bd9Sstevel@tonic-gate 			create_kstats(state);
7497c478bd9Sstevel@tonic-gate 		break;
7507c478bd9Sstevel@tonic-gate 	}
7517c478bd9Sstevel@tonic-gate 
7527c478bd9Sstevel@tonic-gate 	if (error > 0) {
7537c478bd9Sstevel@tonic-gate 		KINCR(pks_ctlserr);
7547c478bd9Sstevel@tonic-gate 	}
7557c478bd9Sstevel@tonic-gate 	if (state->sa_flags & SAF_LASTMOD) {
7567c478bd9Sstevel@tonic-gate 		freemsg(mp);
7577c478bd9Sstevel@tonic-gate 	} else {
7587c478bd9Sstevel@tonic-gate 		KINCR(pks_ctlsfwd);
7597c478bd9Sstevel@tonic-gate 		putnext(q, mp);
7607c478bd9Sstevel@tonic-gate 	}
7617c478bd9Sstevel@tonic-gate }
7627c478bd9Sstevel@tonic-gate 
7637c478bd9Sstevel@tonic-gate /*
7647c478bd9Sstevel@tonic-gate  * spppasyn_wput()
7657c478bd9Sstevel@tonic-gate  *
7667c478bd9Sstevel@tonic-gate  * MT-Perimeters:
7677c478bd9Sstevel@tonic-gate  *	exclusive inner.
7687c478bd9Sstevel@tonic-gate  *
7697c478bd9Sstevel@tonic-gate  * Write side put routine.  This called by the modules above us (likely to
7707c478bd9Sstevel@tonic-gate  * be the compression module) to transmit data or pass along ioctls.
7717c478bd9Sstevel@tonic-gate  */
7727c478bd9Sstevel@tonic-gate static int
spppasyn_wput(queue_t * q,mblk_t * mp)7737c478bd9Sstevel@tonic-gate spppasyn_wput(queue_t *q, mblk_t *mp)
7747c478bd9Sstevel@tonic-gate {
7757c478bd9Sstevel@tonic-gate 	sppp_ahdlc_t		*state;
7767c478bd9Sstevel@tonic-gate 	struct iocblk		*iop;
7777c478bd9Sstevel@tonic-gate 	int			error;
7787c478bd9Sstevel@tonic-gate 	mblk_t			*np;
7797c478bd9Sstevel@tonic-gate 	struct ppp_stats64	*psp;
7807c478bd9Sstevel@tonic-gate 	int			msglen;
7817c478bd9Sstevel@tonic-gate 
7827c478bd9Sstevel@tonic-gate 	ASSERT(q != NULL && mp != NULL);
7837c478bd9Sstevel@tonic-gate 	state = (sppp_ahdlc_t *)q->q_ptr;
7847c478bd9Sstevel@tonic-gate 	ASSERT(state != NULL);
7857c478bd9Sstevel@tonic-gate 
7867c478bd9Sstevel@tonic-gate 	switch (MTYPE(mp)) {
7877c478bd9Sstevel@tonic-gate 
7887c478bd9Sstevel@tonic-gate 	case M_DATA:
7897c478bd9Sstevel@tonic-gate 		/*
7907c478bd9Sstevel@tonic-gate 		 * A data packet - do character-stuffing and FCS, and
7917c478bd9Sstevel@tonic-gate 		 * send it onwards.  The blocks are freed as we go.
7927c478bd9Sstevel@tonic-gate 		 */
7937c478bd9Sstevel@tonic-gate 		if (IS_XMUX_ENABLED(state))
7947c478bd9Sstevel@tonic-gate 			mp = spppasyn_muxencode(q, mp);
7957c478bd9Sstevel@tonic-gate 		else
7967c478bd9Sstevel@tonic-gate 			mp = ahdlc_encode(q, mp);
7977c478bd9Sstevel@tonic-gate 		if (mp != NULL)
7987c478bd9Sstevel@tonic-gate 			putnext(q, mp);
7997c478bd9Sstevel@tonic-gate 		break;
8007c478bd9Sstevel@tonic-gate 
8017c478bd9Sstevel@tonic-gate 	case M_IOCTL:
8027c478bd9Sstevel@tonic-gate 
8037c478bd9Sstevel@tonic-gate 		KINCR(pks_ioctls);
8047c478bd9Sstevel@tonic-gate 		iop = (struct iocblk *)mp->b_rptr;
8057c478bd9Sstevel@tonic-gate 
8067c478bd9Sstevel@tonic-gate 		msglen = 0;
8077c478bd9Sstevel@tonic-gate 
8087c478bd9Sstevel@tonic-gate 		switch (iop->ioc_cmd) {
8097c478bd9Sstevel@tonic-gate 		case PPPIO_XFCS:
8107c478bd9Sstevel@tonic-gate 		case PPPIO_RFCS:
8117c478bd9Sstevel@tonic-gate 		case PPPIO_XACCM:
8127c478bd9Sstevel@tonic-gate 		case PPPIO_RACCM:
8137c478bd9Sstevel@tonic-gate 		case PPPIO_LASTMOD:
8147c478bd9Sstevel@tonic-gate 		case PPPIO_DEBUG:
8157c478bd9Sstevel@tonic-gate 		case PPPIO_MUX:
8167c478bd9Sstevel@tonic-gate 		case PPPIO_CFLAGS:
8177c478bd9Sstevel@tonic-gate 			spppasyn_inner_ioctl(q, mp);
8187c478bd9Sstevel@tonic-gate 			return (0);
8197c478bd9Sstevel@tonic-gate 
8207c478bd9Sstevel@tonic-gate 		case PPPIO_GCLEAN:
8217c478bd9Sstevel@tonic-gate 			np = allocb(sizeof (uint32_t), BPRI_HI);
8227c478bd9Sstevel@tonic-gate 			if (np == NULL) {
8237c478bd9Sstevel@tonic-gate 				error = ENOSR;
8247c478bd9Sstevel@tonic-gate 				break;
8257c478bd9Sstevel@tonic-gate 			}
8267c478bd9Sstevel@tonic-gate 			if (mp->b_cont != NULL) {
8277c478bd9Sstevel@tonic-gate 				freemsg(mp->b_cont);
8287c478bd9Sstevel@tonic-gate 			}
8297c478bd9Sstevel@tonic-gate 			mp->b_cont = np;
8307c478bd9Sstevel@tonic-gate 
8317c478bd9Sstevel@tonic-gate 			*(uint32_t *)np->b_wptr = state->sa_flags & RCV_FLAGS;
8327c478bd9Sstevel@tonic-gate 
8337c478bd9Sstevel@tonic-gate 			msglen = sizeof (uint32_t);
8347c478bd9Sstevel@tonic-gate 			np->b_wptr += msglen;
8357c478bd9Sstevel@tonic-gate 			error = 0;
8367c478bd9Sstevel@tonic-gate 			break;
8377c478bd9Sstevel@tonic-gate 
8387c478bd9Sstevel@tonic-gate 		case PPPIO_GETSTAT:
8397c478bd9Sstevel@tonic-gate 			error = EINVAL;
8407c478bd9Sstevel@tonic-gate 			break;
8417c478bd9Sstevel@tonic-gate 
8427c478bd9Sstevel@tonic-gate 		case PPPIO_GETSTAT64:
8437c478bd9Sstevel@tonic-gate 			np = allocb(sizeof (*psp), BPRI_HI);
8447c478bd9Sstevel@tonic-gate 			if (np == NULL) {
8457c478bd9Sstevel@tonic-gate 				error = ENOSR;
8467c478bd9Sstevel@tonic-gate 				break;
8477c478bd9Sstevel@tonic-gate 			}
8487c478bd9Sstevel@tonic-gate 			if (mp->b_cont != NULL) {
8497c478bd9Sstevel@tonic-gate 				freemsg(mp->b_cont);
8507c478bd9Sstevel@tonic-gate 			}
8517c478bd9Sstevel@tonic-gate 			mp->b_cont = np;
8527c478bd9Sstevel@tonic-gate 
8537c478bd9Sstevel@tonic-gate 			psp = (struct ppp_stats64 *)np->b_wptr;
8547c478bd9Sstevel@tonic-gate 			bzero((caddr_t)psp, sizeof (*psp));
8557c478bd9Sstevel@tonic-gate 			psp->p = state->sa_stats;
8567c478bd9Sstevel@tonic-gate 
8577c478bd9Sstevel@tonic-gate 			msglen = sizeof (*psp);
8587c478bd9Sstevel@tonic-gate 			np->b_wptr += msglen;
8597c478bd9Sstevel@tonic-gate 			error = 0;
8607c478bd9Sstevel@tonic-gate 			break;
8617c478bd9Sstevel@tonic-gate 
8627c478bd9Sstevel@tonic-gate 		case PPPIO_GTYPE:
8637c478bd9Sstevel@tonic-gate 			np = allocb(sizeof (uint32_t), BPRI_HI);
8647c478bd9Sstevel@tonic-gate 			if (np == NULL) {
8657c478bd9Sstevel@tonic-gate 				error = ENOSR;
8667c478bd9Sstevel@tonic-gate 				break;
8677c478bd9Sstevel@tonic-gate 			}
8687c478bd9Sstevel@tonic-gate 			if (mp->b_cont != NULL) {
8697c478bd9Sstevel@tonic-gate 				freemsg(mp->b_cont);
8707c478bd9Sstevel@tonic-gate 			}
8717c478bd9Sstevel@tonic-gate 			mp->b_cont = np;
8727c478bd9Sstevel@tonic-gate 
8737c478bd9Sstevel@tonic-gate 			*(uint32_t *)np->b_wptr = PPPTYP_AHDLC;
8747c478bd9Sstevel@tonic-gate 
8757c478bd9Sstevel@tonic-gate 			msglen = sizeof (uint32_t);
8767c478bd9Sstevel@tonic-gate 			np->b_wptr += msglen;
8777c478bd9Sstevel@tonic-gate 			error = 0;
8787c478bd9Sstevel@tonic-gate 			break;
8797c478bd9Sstevel@tonic-gate 
8807c478bd9Sstevel@tonic-gate 		default:
8817c478bd9Sstevel@tonic-gate 			/* Unknown ioctl -- forward along */
8827c478bd9Sstevel@tonic-gate 			KINCR(pks_ioctlsfwd);
8837c478bd9Sstevel@tonic-gate 			putnext(q, mp);
8847c478bd9Sstevel@tonic-gate 			return (0);
8857c478bd9Sstevel@tonic-gate 		}
8867c478bd9Sstevel@tonic-gate 
8877c478bd9Sstevel@tonic-gate 		if (error == 0) {
8887c478bd9Sstevel@tonic-gate 			/* Success; tell the user */
8897c478bd9Sstevel@tonic-gate 			miocack(q, mp, msglen, 0);
8907c478bd9Sstevel@tonic-gate 		} else {
8917c478bd9Sstevel@tonic-gate 			/* Failure; send error back upstream. */
8927c478bd9Sstevel@tonic-gate 			KINCR(pks_ioctlserr);
8937c478bd9Sstevel@tonic-gate 			miocnak(q, mp, 0, error);
8947c478bd9Sstevel@tonic-gate 		}
8957c478bd9Sstevel@tonic-gate 
8967c478bd9Sstevel@tonic-gate 		break;
8977c478bd9Sstevel@tonic-gate 
8987c478bd9Sstevel@tonic-gate 	case M_CTL:
8997c478bd9Sstevel@tonic-gate 		KINCR(pks_ctls);
9007c478bd9Sstevel@tonic-gate 		spppasyn_inner_mctl(q, mp);
9017c478bd9Sstevel@tonic-gate 		break;
9027c478bd9Sstevel@tonic-gate 
9037c478bd9Sstevel@tonic-gate 	default:
9047c478bd9Sstevel@tonic-gate 		if (state->sa_flags & (SAF_XMITDUMP|SAF_RECVDUMP))
9057c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT,
9067c478bd9Sstevel@tonic-gate 			    "spppasyn_wpur:  unknown buffer type %d",
9077c478bd9Sstevel@tonic-gate 			    MTYPE(mp));
9087c478bd9Sstevel@tonic-gate 		KINCR(pks_unknownwrs);
9097c478bd9Sstevel@tonic-gate 		putnext(q, mp);
9107c478bd9Sstevel@tonic-gate 		break;
9117c478bd9Sstevel@tonic-gate 	}
9127c478bd9Sstevel@tonic-gate 
9137c478bd9Sstevel@tonic-gate 	return (0);
9147c478bd9Sstevel@tonic-gate }
9157c478bd9Sstevel@tonic-gate 
9167c478bd9Sstevel@tonic-gate /*
9177c478bd9Sstevel@tonic-gate  * spppasyn_rput()
9187c478bd9Sstevel@tonic-gate  *
9197c478bd9Sstevel@tonic-gate  * MT-Perimeters:
9207c478bd9Sstevel@tonic-gate  *	exclusive inner.
9217c478bd9Sstevel@tonic-gate  *
9227c478bd9Sstevel@tonic-gate  * Read side put routine.  This is called by the async serial driver
9237c478bd9Sstevel@tonic-gate  * below us to handle received data and returned signals (like
9247c478bd9Sstevel@tonic-gate  * hang-up).
9257c478bd9Sstevel@tonic-gate  */
9267c478bd9Sstevel@tonic-gate static int
spppasyn_rput(queue_t * q,mblk_t * mp)9277c478bd9Sstevel@tonic-gate spppasyn_rput(queue_t *q, mblk_t  *mp)
9287c478bd9Sstevel@tonic-gate {
9297c478bd9Sstevel@tonic-gate 	sppp_ahdlc_t	*state;
9307c478bd9Sstevel@tonic-gate 	mblk_t		*mpnext;
9317c478bd9Sstevel@tonic-gate 
9327c478bd9Sstevel@tonic-gate 	ASSERT(q != NULL && mp != NULL);
9337c478bd9Sstevel@tonic-gate 	state = (sppp_ahdlc_t *)q->q_ptr;
9347c478bd9Sstevel@tonic-gate 	ASSERT(state != NULL);
9357c478bd9Sstevel@tonic-gate 
9367c478bd9Sstevel@tonic-gate 	switch (MTYPE(mp)) {
9377c478bd9Sstevel@tonic-gate 
9387c478bd9Sstevel@tonic-gate 	case M_DATA:
9397c478bd9Sstevel@tonic-gate 		/* Note -- decoder frees the buffers */
9407c478bd9Sstevel@tonic-gate 		mp = ahdlc_decode(q, mp);
9417c478bd9Sstevel@tonic-gate 		while (mp != NULL) {
9427c478bd9Sstevel@tonic-gate 			mpnext = mp->b_next;
9437c478bd9Sstevel@tonic-gate 			mp->b_next = NULL;
9447c478bd9Sstevel@tonic-gate 			putnext(q, mp);
9457c478bd9Sstevel@tonic-gate 			mp = mpnext;
9467c478bd9Sstevel@tonic-gate 		}
9477c478bd9Sstevel@tonic-gate 		break;
9487c478bd9Sstevel@tonic-gate 
9497c478bd9Sstevel@tonic-gate 	case M_HANGUP:
9507c478bd9Sstevel@tonic-gate 		KINCR(pks_hangups);
9517c478bd9Sstevel@tonic-gate 		state->sa_flags |= SAF_IFLUSH;
9527c478bd9Sstevel@tonic-gate 		putnext(q, mp);
9537c478bd9Sstevel@tonic-gate 		break;
9547c478bd9Sstevel@tonic-gate 
9557c478bd9Sstevel@tonic-gate 	default:
9567c478bd9Sstevel@tonic-gate 		if (state->sa_flags & (SAF_XMITDUMP|SAF_RECVDUMP)) {
9577c478bd9Sstevel@tonic-gate 			if (MTYPE(mp) == M_IOCTL)
9587c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT,
9597c478bd9Sstevel@tonic-gate 				    "spppasyn_rput:  unexpected ioctl %X",
9607c478bd9Sstevel@tonic-gate 				    ((struct iocblk *)mp->b_rptr)->ioc_cmd);
9617c478bd9Sstevel@tonic-gate 			else
9627c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT,
9637c478bd9Sstevel@tonic-gate 				    "spppasyn_rput:  unknown buffer type %d",
9647c478bd9Sstevel@tonic-gate 				    MTYPE(mp));
9657c478bd9Sstevel@tonic-gate 		}
9667c478bd9Sstevel@tonic-gate 		KINCR(pks_unknownrds);
9677c478bd9Sstevel@tonic-gate 		putnext(q, mp);
9687c478bd9Sstevel@tonic-gate 		break;
9697c478bd9Sstevel@tonic-gate 	}
9707c478bd9Sstevel@tonic-gate 
9717c478bd9Sstevel@tonic-gate 	return (0);
9727c478bd9Sstevel@tonic-gate }
9737c478bd9Sstevel@tonic-gate 
9747c478bd9Sstevel@tonic-gate /*
9757c478bd9Sstevel@tonic-gate  * ahdlc_encode
9767c478bd9Sstevel@tonic-gate  *
9777c478bd9Sstevel@tonic-gate  * Perform asynchronous HDLC framing on a given buffer and transmit
9787c478bd9Sstevel@tonic-gate  * the result.  The state structure must be valid.  The input buffers
9797c478bd9Sstevel@tonic-gate  * are freed as we go.
9807c478bd9Sstevel@tonic-gate  *
9817c478bd9Sstevel@tonic-gate  * This function is called by wput and just encodes the data.  Wput
9827c478bd9Sstevel@tonic-gate  * then calls putnext directly.  There's no service routine for this
9837c478bd9Sstevel@tonic-gate  * module, so flow control is asserted by the module below us up to
9847c478bd9Sstevel@tonic-gate  * our caller by the STREAMS framework.  This is by design -- this
9857c478bd9Sstevel@tonic-gate  * module does not queue anything so that other modules can make QoS
9867c478bd9Sstevel@tonic-gate  * decisions.
9877c478bd9Sstevel@tonic-gate  */
9887c478bd9Sstevel@tonic-gate static mblk_t *
ahdlc_encode(queue_t * q,mblk_t * mp)9897c478bd9Sstevel@tonic-gate ahdlc_encode(queue_t *q, mblk_t	*mp)
9907c478bd9Sstevel@tonic-gate {
9917c478bd9Sstevel@tonic-gate 	sppp_ahdlc_t	*state;
9927c478bd9Sstevel@tonic-gate 	uint32_t	loc_xaccm[8];
9937c478bd9Sstevel@tonic-gate 	ushort_t	fcs16;
9947c478bd9Sstevel@tonic-gate 	uint32_t	fcs32;
9957c478bd9Sstevel@tonic-gate 	size_t		msglen;
9967c478bd9Sstevel@tonic-gate 	size_t		outmp_len;
9977c478bd9Sstevel@tonic-gate 	mblk_t		*outmp;
9987c478bd9Sstevel@tonic-gate 	mblk_t		*curout;
9997c478bd9Sstevel@tonic-gate 	mblk_t		*tmp;
10007c478bd9Sstevel@tonic-gate 	uchar_t		*ep;
10017c478bd9Sstevel@tonic-gate 	uchar_t		*dp;
10027c478bd9Sstevel@tonic-gate 	uchar_t		*tp;
10037c478bd9Sstevel@tonic-gate 	uchar_t		*tpmax;
10047c478bd9Sstevel@tonic-gate #if defined(lint) || defined(_lint)
10057c478bd9Sstevel@tonic-gate 	uchar_t		chr;	/* lint likes this */
10067c478bd9Sstevel@tonic-gate #else
10077c478bd9Sstevel@tonic-gate 	int		chr;	/* not uchar_t; more efficient this way */
10087c478bd9Sstevel@tonic-gate 				/* with WorkShop compiler */
10097c478bd9Sstevel@tonic-gate #endif
10107c478bd9Sstevel@tonic-gate 	int		is_lcp, is_ctrl;
10117c478bd9Sstevel@tonic-gate 	int		code;
10127c478bd9Sstevel@tonic-gate 	hrtime_t	hrtime;
10137c478bd9Sstevel@tonic-gate 	uint32_t	flags;	/* sampled copy of flags */
10147c478bd9Sstevel@tonic-gate 
10157c478bd9Sstevel@tonic-gate 	state = (sppp_ahdlc_t *)q->q_ptr;
10167c478bd9Sstevel@tonic-gate 
10177c478bd9Sstevel@tonic-gate 	/* Don't transmit anything obviously silly. */
10187c478bd9Sstevel@tonic-gate 	msglen = msgsize(mp);
10197c478bd9Sstevel@tonic-gate 	if (msglen < 4) {
10207c478bd9Sstevel@tonic-gate 		KINCR(pks_outrunts);
10217c478bd9Sstevel@tonic-gate 		freemsg(mp);
10227c478bd9Sstevel@tonic-gate 		(void) putnextctl1(RD(q), M_CTL, PPPCTL_OERROR);
10237c478bd9Sstevel@tonic-gate 		return (NULL);
10247c478bd9Sstevel@tonic-gate 	}
10257c478bd9Sstevel@tonic-gate 
10267c478bd9Sstevel@tonic-gate 	/*
10277c478bd9Sstevel@tonic-gate 	 * Allocate an output buffer just large enough for most cases.
10287c478bd9Sstevel@tonic-gate 	 * Based on original work in the ppp-2.2 AIX PPP driver, we
10297c478bd9Sstevel@tonic-gate 	 * estimate the output size as 1.25 * input message length
10307c478bd9Sstevel@tonic-gate 	 * plus 16.  If this turns out to be too small, then we'll
10317c478bd9Sstevel@tonic-gate 	 * allocate exactly one additional buffer with two times the
10327c478bd9Sstevel@tonic-gate 	 * remaining input length (the maximum that could possibly be
10337c478bd9Sstevel@tonic-gate 	 * required).
10347c478bd9Sstevel@tonic-gate 	 */
10357c478bd9Sstevel@tonic-gate 	outmp_len = msglen + (msglen >> 2) + 16;
10367c478bd9Sstevel@tonic-gate 	outmp = allocb(outmp_len, BPRI_MED);
10377c478bd9Sstevel@tonic-gate 	if (outmp == NULL)
10387c478bd9Sstevel@tonic-gate 		goto outallocfail;
10397c478bd9Sstevel@tonic-gate 
10407c478bd9Sstevel@tonic-gate 	tp = outmp->b_wptr;
10417c478bd9Sstevel@tonic-gate 
10427c478bd9Sstevel@tonic-gate 	/*
10437c478bd9Sstevel@tonic-gate 	 * Check if our last transmit happened within FLAG_TIME, using
10447c478bd9Sstevel@tonic-gate 	 * the system's hrtime.
10457c478bd9Sstevel@tonic-gate 	 */
10467c478bd9Sstevel@tonic-gate 	hrtime = gethrtime();
10477c478bd9Sstevel@tonic-gate 	if (ABS(hrtime - state->sa_hrtime) > FLAG_TIME) {
10487c478bd9Sstevel@tonic-gate 		*tp++ = PPP_FLAG;
10497c478bd9Sstevel@tonic-gate 	}
10507c478bd9Sstevel@tonic-gate 	state->sa_hrtime = hrtime;
10517c478bd9Sstevel@tonic-gate 	bcopy((caddr_t)state->sa_xaccm, (caddr_t)loc_xaccm, sizeof (loc_xaccm));
10527c478bd9Sstevel@tonic-gate 	flags = state->sa_flags;
10537c478bd9Sstevel@tonic-gate 
10547c478bd9Sstevel@tonic-gate 	/*
10557c478bd9Sstevel@tonic-gate 	 * LCP messages must be sent using the default escaping
10567c478bd9Sstevel@tonic-gate 	 * (ACCM).  We bend this rule a little to allow LCP
10577c478bd9Sstevel@tonic-gate 	 * Echo-Request through with the negotiated escaping so that
10587c478bd9Sstevel@tonic-gate 	 * we can detect bad negotiated ACCM values.  If the ACCM is
10597c478bd9Sstevel@tonic-gate 	 * bad, echos will fail and take down the link.
10607c478bd9Sstevel@tonic-gate 	 */
10617c478bd9Sstevel@tonic-gate 	is_lcp = is_ctrl = 0;
10627c478bd9Sstevel@tonic-gate 	code = MSG_BYTE(mp, 0);
10637c478bd9Sstevel@tonic-gate 	if (code == PPP_ALLSTATIONS) {
10647c478bd9Sstevel@tonic-gate 		if (MSG_BYTE(mp, 1) == PPP_UI) {
10657c478bd9Sstevel@tonic-gate 			code = MSG_BYTE(mp, 2);
10667c478bd9Sstevel@tonic-gate 			if (code == (PPP_LCP >> 8) &&
10677c478bd9Sstevel@tonic-gate 			    MSG_BYTE(mp, 3) == (PPP_LCP & 0xFF)) {
10687c478bd9Sstevel@tonic-gate 				if (LCP_USE_DFLT(mp))
10697c478bd9Sstevel@tonic-gate 					is_lcp = 2;
10707c478bd9Sstevel@tonic-gate 				else
10717c478bd9Sstevel@tonic-gate 					is_lcp = 1;	/* Echo-Request */
10727c478bd9Sstevel@tonic-gate 			} else if (!(code & 1) && code > 0x3F)
10737c478bd9Sstevel@tonic-gate 				is_ctrl = 1;
10747c478bd9Sstevel@tonic-gate 		}
10757c478bd9Sstevel@tonic-gate 	} else if (!(code & 1) && code > 0x3F)
10767c478bd9Sstevel@tonic-gate 		is_ctrl = 1;
10777c478bd9Sstevel@tonic-gate 
10787c478bd9Sstevel@tonic-gate 	/*
10797c478bd9Sstevel@tonic-gate 	 * If it's LCP and not just an LCP Echo-Request, then we need
10807c478bd9Sstevel@tonic-gate 	 * to drop back to default escaping rules temporarily.
10817c478bd9Sstevel@tonic-gate 	 */
10827c478bd9Sstevel@tonic-gate 	if (is_lcp > 1) {
10837c478bd9Sstevel@tonic-gate 		/*
10847c478bd9Sstevel@tonic-gate 		 * force escape on 0x00 through 0x1f
10857c478bd9Sstevel@tonic-gate 		 * and, for RFC 1662 (and ISO 3309:1991), 0x80-0x9f.
10867c478bd9Sstevel@tonic-gate 		 */
10877c478bd9Sstevel@tonic-gate 		loc_xaccm[0] = 0xffffffff;
10887c478bd9Sstevel@tonic-gate 		loc_xaccm[4] = 0xffffffff;
10897c478bd9Sstevel@tonic-gate 	}
10907c478bd9Sstevel@tonic-gate 
10917c478bd9Sstevel@tonic-gate 	fcs16 = PPPINITFCS16;		/* Initial FCS is 0xffff */
10927c478bd9Sstevel@tonic-gate 	fcs32 = PPPINITFCS32;
10937c478bd9Sstevel@tonic-gate 
10947c478bd9Sstevel@tonic-gate 	/*
10957c478bd9Sstevel@tonic-gate 	 * Process this block and the rest (if any) attached to this
10967c478bd9Sstevel@tonic-gate 	 * one.  Note that we quite intentionally ignore the type of
10977c478bd9Sstevel@tonic-gate 	 * the buffer.  The caller has checked that the first buffer
10987c478bd9Sstevel@tonic-gate 	 * is M_DATA; all others must be so, and any that are not are
10997c478bd9Sstevel@tonic-gate 	 * harmless driver errors.
11007c478bd9Sstevel@tonic-gate 	 */
11017c478bd9Sstevel@tonic-gate 	curout = outmp;
11027c478bd9Sstevel@tonic-gate 	tpmax = outmp->b_datap->db_lim;
11037c478bd9Sstevel@tonic-gate 	do {
11047c478bd9Sstevel@tonic-gate 		dp = mp->b_rptr;
11057c478bd9Sstevel@tonic-gate 		while (dp < (ep = mp->b_wptr)) {
11067c478bd9Sstevel@tonic-gate 			/*
11077c478bd9Sstevel@tonic-gate 			 * Calculate maximum safe run length for inner loop,
11087c478bd9Sstevel@tonic-gate 			 * regardless of escaping.
11097c478bd9Sstevel@tonic-gate 			 */
11107c478bd9Sstevel@tonic-gate 			outmp_len = (tpmax - tp) / 2;
11117c478bd9Sstevel@tonic-gate 			if (dp + outmp_len < ep)
11127c478bd9Sstevel@tonic-gate 				ep = dp + outmp_len;
11137c478bd9Sstevel@tonic-gate 
11147c478bd9Sstevel@tonic-gate 			/*
11157c478bd9Sstevel@tonic-gate 			 * Select out on CRC type here to make the
11167c478bd9Sstevel@tonic-gate 			 * inner byte loop more efficient.  (We could
11177c478bd9Sstevel@tonic-gate 			 * do both CRCs at all times if we wanted, but
11187c478bd9Sstevel@tonic-gate 			 * that ends up taking an extra 8 cycles per
11197c478bd9Sstevel@tonic-gate 			 * byte -- 47% overhead!)
11207c478bd9Sstevel@tonic-gate 			 */
11217c478bd9Sstevel@tonic-gate 			if (flags & SAF_XMITCRC32) {
11227c478bd9Sstevel@tonic-gate 				while (dp < ep) {
11237c478bd9Sstevel@tonic-gate 					chr = *dp++;
11247c478bd9Sstevel@tonic-gate 					fcs32 = PPPFCS32(fcs32, chr);
11257c478bd9Sstevel@tonic-gate 					if (IN_TX_MAP(chr, loc_xaccm)) {
11267c478bd9Sstevel@tonic-gate 						*tp++ = PPP_ESCAPE;
11277c478bd9Sstevel@tonic-gate 						chr ^= PPP_TRANS;
11287c478bd9Sstevel@tonic-gate 					}
11297c478bd9Sstevel@tonic-gate 					*