xref: /onnv-gate/usr/src/uts/common/io/ppp/sppp/sppp_dlpi.c (revision 9751:8e29565352fc)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * sppp_dlpi.c - Solaris STREAMS PPP multiplexing pseudo-driver DLPI handlers
30Sstevel@tonic-gate  *
4*9751Sjames.d.carlson@sun.com  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
50Sstevel@tonic-gate  * Use is subject to license terms.
60Sstevel@tonic-gate  *
70Sstevel@tonic-gate  * Permission to use, copy, modify, and distribute this software and its
80Sstevel@tonic-gate  * documentation is hereby granted, provided that the above copyright
90Sstevel@tonic-gate  * notice appears in all copies.
100Sstevel@tonic-gate  *
110Sstevel@tonic-gate  * SUN MAKES NO REPRESENTATION OR WARRANTIES ABOUT THE SUITABILITY OF
120Sstevel@tonic-gate  * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
130Sstevel@tonic-gate  * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
140Sstevel@tonic-gate  * PARTICULAR PURPOSE, OR NON-INFRINGEMENT.  SUN SHALL NOT BE LIABLE FOR
150Sstevel@tonic-gate  * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
160Sstevel@tonic-gate  * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES
170Sstevel@tonic-gate  *
180Sstevel@tonic-gate  * Copyright (c) 1994 The Australian National University.
190Sstevel@tonic-gate  * All rights reserved.
200Sstevel@tonic-gate  *
210Sstevel@tonic-gate  * Permission to use, copy, modify, and distribute this software and its
220Sstevel@tonic-gate  * documentation is hereby granted, provided that the above copyright
230Sstevel@tonic-gate  * notice appears in all copies.  This software is provided without any
240Sstevel@tonic-gate  * warranty, express or implied. The Australian National University
250Sstevel@tonic-gate  * makes no representations about the suitability of this software for
260Sstevel@tonic-gate  * any purpose.
270Sstevel@tonic-gate  *
280Sstevel@tonic-gate  * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
290Sstevel@tonic-gate  * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
300Sstevel@tonic-gate  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
310Sstevel@tonic-gate  * THE AUSTRALIAN NATIONAL UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY
320Sstevel@tonic-gate  * OF SUCH DAMAGE.
330Sstevel@tonic-gate  *
340Sstevel@tonic-gate  * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
350Sstevel@tonic-gate  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
360Sstevel@tonic-gate  * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
370Sstevel@tonic-gate  * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
380Sstevel@tonic-gate  * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
390Sstevel@tonic-gate  * OR MODIFICATIONS.
400Sstevel@tonic-gate  *
410Sstevel@tonic-gate  * This driver is derived from the original SVR4 STREAMS PPP driver
420Sstevel@tonic-gate  * originally written by Paul Mackerras <paul.mackerras@cs.anu.edu.au>.
430Sstevel@tonic-gate  *
440Sstevel@tonic-gate  * Adi Masputra <adi.masputra@sun.com> rewrote and restructured the code
450Sstevel@tonic-gate  * for improved performance and scalability.
460Sstevel@tonic-gate  */
470Sstevel@tonic-gate 
480Sstevel@tonic-gate #define	RCSID	"$Id: sppp_dlpi.c,v 1.0 2000/05/08 01:10:12 masputra Exp $"
490Sstevel@tonic-gate 
500Sstevel@tonic-gate #include <sys/types.h>
510Sstevel@tonic-gate #include <sys/param.h>
520Sstevel@tonic-gate #include <sys/stat.h>
530Sstevel@tonic-gate #include <sys/stream.h>
540Sstevel@tonic-gate #include <sys/stropts.h>
550Sstevel@tonic-gate #include <sys/errno.h>
560Sstevel@tonic-gate #include <sys/time.h>
570Sstevel@tonic-gate #include <sys/cmn_err.h>
580Sstevel@tonic-gate #include <sys/conf.h>
590Sstevel@tonic-gate #include <sys/dlpi.h>
600Sstevel@tonic-gate #include <sys/ddi.h>
610Sstevel@tonic-gate #include <sys/kstat.h>
62*9751Sjames.d.carlson@sun.com #include <sys/strsubr.h>
630Sstevel@tonic-gate #include <sys/strsun.h>
640Sstevel@tonic-gate #include <sys/ethernet.h>
650Sstevel@tonic-gate #include <net/ppp_defs.h>
660Sstevel@tonic-gate #include <netinet/in.h>
670Sstevel@tonic-gate #include <net/pppio.h>
680Sstevel@tonic-gate #include "s_common.h"
690Sstevel@tonic-gate #include "sppp.h"
700Sstevel@tonic-gate 
710Sstevel@tonic-gate static int	sppp_dlattachreq(queue_t *, mblk_t *, spppstr_t *);
720Sstevel@tonic-gate static int	sppp_dldetachreq(queue_t *, mblk_t *, spppstr_t *);
730Sstevel@tonic-gate static int	sppp_dlbindreq(queue_t *, mblk_t *, spppstr_t *);
740Sstevel@tonic-gate static int	sppp_dlunbindreq(queue_t *, mblk_t *, spppstr_t *);
750Sstevel@tonic-gate static int	sppp_dlinforeq(queue_t *, mblk_t *, spppstr_t *);
760Sstevel@tonic-gate static int	sppp_dlunitdatareq(queue_t *, mblk_t *, spppstr_t *);
770Sstevel@tonic-gate static int	sppp_dlpromisconreq(queue_t *, mblk_t *, spppstr_t *);
780Sstevel@tonic-gate static int	sppp_dlpromiscoffreq(queue_t *, mblk_t *, spppstr_t *);
790Sstevel@tonic-gate static int	sppp_dlphyreq(queue_t *, mblk_t *, spppstr_t *);
800Sstevel@tonic-gate static void	sppp_dl_attach_upper(queue_t *, mblk_t *);
810Sstevel@tonic-gate static void	sppp_dl_detach_upper(queue_t *, mblk_t *);
820Sstevel@tonic-gate static void	sppp_dl_bind(queue_t *, mblk_t *);
830Sstevel@tonic-gate static void	sppp_dl_unbind(queue_t *, mblk_t *);
840Sstevel@tonic-gate static void	sppp_dl_promiscon(queue_t *, mblk_t *);
850Sstevel@tonic-gate static void	sppp_dl_promiscoff(queue_t *, mblk_t *);
860Sstevel@tonic-gate static mblk_t	*sppp_dladdether(spppstr_t *, mblk_t *, t_scalar_t);
870Sstevel@tonic-gate 
880Sstevel@tonic-gate static struct sppp_dlpi_pinfo_t dl_pinfo[DL_MAXPRIM + 1];
890Sstevel@tonic-gate 
900Sstevel@tonic-gate #if 0
910Sstevel@tonic-gate #define	DBGERROR(x)	cmn_err x
920Sstevel@tonic-gate #else
930Sstevel@tonic-gate #define	DBGERROR(x)	((void)0)
940Sstevel@tonic-gate #endif
950Sstevel@tonic-gate 
960Sstevel@tonic-gate /* #define	DBG_DLPI	1 */
970Sstevel@tonic-gate 
980Sstevel@tonic-gate #ifdef DBG_DLPI
990Sstevel@tonic-gate struct sppp_dlpi_entry {
1000Sstevel@tonic-gate 	uint32_t sde_val;
1010Sstevel@tonic-gate 	const char *sde_name;
1020Sstevel@tonic-gate };
1030Sstevel@tonic-gate 
1040Sstevel@tonic-gate static const struct sppp_dlpi_entry sppp_dlpi_list[] = {
1050Sstevel@tonic-gate 	{ DL_INFO_REQ, "DL_INFO_REQ" },
1060Sstevel@tonic-gate 	{ DL_INFO_ACK, "DL_INFO_ACK" },
1070Sstevel@tonic-gate 	{ DL_ATTACH_REQ, "DL_ATTACH_REQ" },
1080Sstevel@tonic-gate 	{ DL_DETACH_REQ, "DL_DETACH_REQ" },
1090Sstevel@tonic-gate 	{ DL_BIND_REQ, "DL_BIND_REQ" },
1100Sstevel@tonic-gate 	{ DL_BIND_ACK, "DL_BIND_ACK" },
1110Sstevel@tonic-gate 	{ DL_UNBIND_REQ, "DL_UNBIND_REQ" },
1120Sstevel@tonic-gate 	{ DL_OK_ACK, "DL_OK_ACK" },
1130Sstevel@tonic-gate 	{ DL_ERROR_ACK, "DL_ERROR_ACK" },
1140Sstevel@tonic-gate 	{ DL_SUBS_BIND_REQ, "DL_SUBS_BIND_REQ" },
1150Sstevel@tonic-gate 	{ DL_SUBS_BIND_ACK, "DL_SUBS_BIND_ACK" },
1160Sstevel@tonic-gate 	{ DL_SUBS_UNBIND_REQ, "DL_SUBS_UNBIND_REQ" },
1170Sstevel@tonic-gate 	{ DL_ENABMULTI_REQ, "DL_ENABMULTI_REQ" },
1180Sstevel@tonic-gate 	{ DL_DISABMULTI_REQ, "DL_DISABMULTI_REQ" },
1190Sstevel@tonic-gate 	{ DL_PROMISCON_REQ, "DL_PROMISCON_REQ" },
1200Sstevel@tonic-gate 	{ DL_PROMISCOFF_REQ, "DL_PROMISCOFF_REQ" },
1210Sstevel@tonic-gate 	{ DL_UNITDATA_REQ, "DL_UNITDATA_REQ" },
1220Sstevel@tonic-gate 	{ DL_UNITDATA_IND, "DL_UNITDATA_IND" },
1230Sstevel@tonic-gate 	{ DL_UDERROR_IND, "DL_UDERROR_IND" },
1240Sstevel@tonic-gate 	{ DL_UDQOS_REQ, "DL_UDQOS_REQ" },
1250Sstevel@tonic-gate 	{ DL_CONNECT_REQ, "DL_CONNECT_REQ" },
1260Sstevel@tonic-gate 	{ DL_CONNECT_IND, "DL_CONNECT_IND" },
1270Sstevel@tonic-gate 	{ DL_CONNECT_RES, "DL_CONNECT_RES" },
1280Sstevel@tonic-gate 	{ DL_CONNECT_CON, "DL_CONNECT_CON" },
1290Sstevel@tonic-gate 	{ DL_TOKEN_REQ, "DL_TOKEN_REQ" },
1300Sstevel@tonic-gate 	{ DL_TOKEN_ACK, "DL_TOKEN_ACK" },
1310Sstevel@tonic-gate 	{ DL_DISCONNECT_REQ, "DL_DISCONNECT_REQ" },
1320Sstevel@tonic-gate 	{ DL_DISCONNECT_IND, "DL_DISCONNECT_IND" },
1330Sstevel@tonic-gate 	{ DL_RESET_REQ, "DL_RESET_REQ" },
1340Sstevel@tonic-gate 	{ DL_RESET_IND, "DL_RESET_IND" },
1350Sstevel@tonic-gate 	{ DL_RESET_RES, "DL_RESET_RES" },
1360Sstevel@tonic-gate 	{ DL_RESET_CON, "DL_RESET_CON" },
1370Sstevel@tonic-gate 	{ DL_DATA_ACK_REQ, "DL_DATA_ACK_REQ" },
1380Sstevel@tonic-gate 	{ DL_DATA_ACK_IND, "DL_DATA_ACK_IND" },
1390Sstevel@tonic-gate 	{ DL_DATA_ACK_STATUS_IND, "DL_DATA_ACK_STATUS_IND" },
1400Sstevel@tonic-gate 	{ DL_REPLY_REQ, "DL_REPLY_REQ" },
1410Sstevel@tonic-gate 	{ DL_REPLY_IND, "DL_REPLY_IND" },
1420Sstevel@tonic-gate 	{ DL_REPLY_STATUS_IND, "DL_REPLY_STATUS_IND" },
1430Sstevel@tonic-gate 	{ DL_REPLY_UPDATE_REQ, "DL_REPLY_UPDATE_REQ" },
1440Sstevel@tonic-gate 	{ DL_REPLY_UPDATE_STATUS_IND, "DL_REPLY_UPDATE_STATUS_IND" },
1450Sstevel@tonic-gate 	{ DL_XID_REQ, "DL_XID_REQ" },
1460Sstevel@tonic-gate 	{ DL_XID_IND, "DL_XID_IND" },
1470Sstevel@tonic-gate 	{ DL_XID_RES, "DL_XID_RES" },
1480Sstevel@tonic-gate 	{ DL_XID_CON, "DL_XID_CON" },
1490Sstevel@tonic-gate 	{ DL_TEST_REQ, "DL_TEST_REQ" },
1500Sstevel@tonic-gate 	{ DL_TEST_IND, "DL_TEST_IND" },
1510Sstevel@tonic-gate 	{ DL_TEST_RES, "DL_TEST_RES" },
1520Sstevel@tonic-gate 	{ DL_TEST_CON, "DL_TEST_CON" },
1530Sstevel@tonic-gate 	{ DL_PHYS_ADDR_REQ, "DL_PHYS_ADDR_REQ" },
1540Sstevel@tonic-gate 	{ DL_PHYS_ADDR_ACK, "DL_PHYS_ADDR_ACK" },
1550Sstevel@tonic-gate 	{ DL_SET_PHYS_ADDR_REQ, "DL_SET_PHYS_ADDR_REQ" },
1560Sstevel@tonic-gate 	{ DL_GET_STATISTICS_REQ, "DL_GET_STATISTICS_REQ" },
1570Sstevel@tonic-gate 	{ DL_GET_STATISTICS_ACK, "DL_GET_STATISTICS_ACK" },
1580Sstevel@tonic-gate 	{ 0, NULL }
1590Sstevel@tonic-gate };
1600Sstevel@tonic-gate 
1610Sstevel@tonic-gate static const struct sppp_dlpi_entry sppp_state_list[] = {
1620Sstevel@tonic-gate 	{ DL_UNBOUND, "DL_UNBOUND" },
1630Sstevel@tonic-gate 	{ DL_BIND_PENDING, "DL_BIND_PENDING" },
1640Sstevel@tonic-gate 	{ DL_UNBIND_PENDING, "DL_UNBIND_PENDING" },
1650Sstevel@tonic-gate 	{ DL_IDLE, "DL_IDLE" },
1660Sstevel@tonic-gate 	{ DL_UNATTACHED, "DL_UNATTACHED" },
1670Sstevel@tonic-gate 	{ DL_ATTACH_PENDING, "DL_ATTACH_PENDING" },
1680Sstevel@tonic-gate 	{ DL_DETACH_PENDING, "DL_DETACH_PENDING" },
1690Sstevel@tonic-gate 	{ DL_UDQOS_PENDING, "DL_UDQOS_PENDING" },
1700Sstevel@tonic-gate 	{ DL_OUTCON_PENDING, "DL_OUTCON_PENDING" },
1710Sstevel@tonic-gate 	{ DL_INCON_PENDING, "DL_INCON_PENDING" },
1720Sstevel@tonic-gate 	{ DL_CONN_RES_PENDING, "DL_CONN_RES_PENDING" },
1730Sstevel@tonic-gate 	{ DL_DATAXFER, "DL_DATAXFER" },
1740Sstevel@tonic-gate 	{ DL_USER_RESET_PENDING, "DL_USER_RESET_PENDING" },
1750Sstevel@tonic-gate 	{ DL_PROV_RESET_PENDING, "DL_PROV_RESET_PENDING" },
1760Sstevel@tonic-gate 	{ DL_RESET_RES_PENDING, "DL_RESET_RES_PENDING" },
1770Sstevel@tonic-gate 	{ DL_DISCON8_PENDING, "DL_DISCON8_PENDING" },
1780Sstevel@tonic-gate 	{ DL_DISCON9_PENDING, "DL_DISCON9_PENDING" },
1790Sstevel@tonic-gate 	{ DL_DISCON11_PENDING, "DL_DISCON11_PENDING" },
1800Sstevel@tonic-gate 	{ DL_DISCON12_PENDING, "DL_DISCON12_PENDING" },
1810Sstevel@tonic-gate 	{ DL_DISCON13_PENDING, "DL_DISCON13_PENDING" },
1820Sstevel@tonic-gate 	{ DL_SUBS_BIND_PND, "DL_SUBS_BIND_PND" },
1830Sstevel@tonic-gate 	{ DL_SUBS_UNBIND_PND, "DL_SUBS_UNBIND_PND" },
1840Sstevel@tonic-gate 	{ 0, NULL }
1850Sstevel@tonic-gate };
1860Sstevel@tonic-gate 
1870Sstevel@tonic-gate static const char *
prim2name(uint32_t prim)1880Sstevel@tonic-gate prim2name(uint32_t prim)
1890Sstevel@tonic-gate {
1900Sstevel@tonic-gate 	const struct sppp_dlpi_entry *sde;
1910Sstevel@tonic-gate 
1920Sstevel@tonic-gate 	for (sde = sppp_dlpi_list; sde->sde_name != NULL; sde++)
1930Sstevel@tonic-gate 		if (sde->sde_val == prim)
1940Sstevel@tonic-gate 			break;
1950Sstevel@tonic-gate 	return (sde->sde_name);
1960Sstevel@tonic-gate }
1970Sstevel@tonic-gate 
1980Sstevel@tonic-gate static const char *
state2name(uint32_t state)1990Sstevel@tonic-gate state2name(uint32_t state)
2000Sstevel@tonic-gate {
2010Sstevel@tonic-gate 	const struct sppp_dlpi_entry *sde;
2020Sstevel@tonic-gate 
2030Sstevel@tonic-gate 	for (sde = sppp_state_list; sde->sde_name != NULL; sde++)
2040Sstevel@tonic-gate 		if (sde->sde_val == state)
2050Sstevel@tonic-gate 			break;
2060Sstevel@tonic-gate 	return (sde->sde_name);
2070Sstevel@tonic-gate }
2080Sstevel@tonic-gate 
2090Sstevel@tonic-gate #define	DBGDLPI(x)	cmn_err x
2100Sstevel@tonic-gate #else
2110Sstevel@tonic-gate #define	DBGDLPI(x)	((void)0)
2120Sstevel@tonic-gate #endif /* DBG_DLPI */
2130Sstevel@tonic-gate 
2140Sstevel@tonic-gate /*
2150Sstevel@tonic-gate  * DL_INFO_ACK template for point-to-point interface.
2160Sstevel@tonic-gate  */
2170Sstevel@tonic-gate static dl_info_ack_t	sppp_infoack = {
2180Sstevel@tonic-gate 	DL_INFO_ACK,			/* dl_primitive */
2190Sstevel@tonic-gate 	PPP_MAXMTU,			/* dl_max_sdu */
2200Sstevel@tonic-gate 	0,				/* dl_min_sdu */
2210Sstevel@tonic-gate 	SPPP_ADDRL,			/* dl_addr_length */
2220Sstevel@tonic-gate 	/*
2230Sstevel@tonic-gate 	 * snoop et. al. don't know about DL_OTHER so this entry
2240Sstevel@tonic-gate 	 * was changed to DL_ETHER so ethernet tracing/snooping
2250Sstevel@tonic-gate 	 * facilities will work with PPP interfaces.
2260Sstevel@tonic-gate 	 */
2270Sstevel@tonic-gate 	DL_ETHER,			/* dl_mac_type */
2280Sstevel@tonic-gate 	0,				/* dl_reserved */
2290Sstevel@tonic-gate 	0,				/* dl_current_state */
2300Sstevel@tonic-gate 	SPPP_SAPL,			/* dl_sap_length */
2310Sstevel@tonic-gate 	DL_CLDLS,			/* dl_service_mode */
2320Sstevel@tonic-gate 	0,				/* dl_qos_length */
2330Sstevel@tonic-gate 	0,				/* dl_qos_offset */
2340Sstevel@tonic-gate 	0,				/* dl_range_length */
2350Sstevel@tonic-gate 	0,				/* dl_range_offset */
2360Sstevel@tonic-gate 	DL_STYLE2,			/* dl_provider_style */
2370Sstevel@tonic-gate 	sizeof (dl_info_ack_t),		/* dl_addr_offset */
2380Sstevel@tonic-gate 	DL_VERSION_2,			/* dl_version */
2390Sstevel@tonic-gate 	0,				/* dl_brdcst_addr_length */
2400Sstevel@tonic-gate 	0,				/* dl_brdcst_addr_offset */
2410Sstevel@tonic-gate 	0				/* dl_growth */
2420Sstevel@tonic-gate };
2430Sstevel@tonic-gate 
2440Sstevel@tonic-gate /*
2450Sstevel@tonic-gate  * sppp_dlpi_pinfoinit()
2460Sstevel@tonic-gate  *
2470Sstevel@tonic-gate  * Description:
2480Sstevel@tonic-gate  *    Initialize dl_pinfo[], called from sppp_attach.
2490Sstevel@tonic-gate  */
2500Sstevel@tonic-gate void
sppp_dlpi_pinfoinit(void)2510Sstevel@tonic-gate sppp_dlpi_pinfoinit(void)
2520Sstevel@tonic-gate {
2530Sstevel@tonic-gate 	bzero(dl_pinfo, sizeof (dl_pinfo));	/* Just to be safe */
2540Sstevel@tonic-gate 
2550Sstevel@tonic-gate 	dl_pinfo[DL_ATTACH_REQ].pi_minlen = sizeof (dl_attach_req_t);
2560Sstevel@tonic-gate 	dl_pinfo[DL_ATTACH_REQ].pi_state = DL_UNATTACHED;
2570Sstevel@tonic-gate 	dl_pinfo[DL_ATTACH_REQ].pi_funcp = sppp_dlattachreq;
2580Sstevel@tonic-gate 
2590Sstevel@tonic-gate 	dl_pinfo[DL_DETACH_REQ].pi_minlen = sizeof (dl_detach_req_t);
2600Sstevel@tonic-gate 	dl_pinfo[DL_DETACH_REQ].pi_state = DL_UNBOUND;
2610Sstevel@tonic-gate 	dl_pinfo[DL_DETACH_REQ].pi_funcp = sppp_dldetachreq;
2620Sstevel@tonic-gate 
2630Sstevel@tonic-gate 	dl_pinfo[DL_BIND_REQ].pi_minlen = sizeof (dl_bind_req_t);
2640Sstevel@tonic-gate 	dl_pinfo[DL_BIND_REQ].pi_state = DL_UNBOUND;
2650Sstevel@tonic-gate 	dl_pinfo[DL_BIND_REQ].pi_funcp = sppp_dlbindreq;
2660Sstevel@tonic-gate 
2670Sstevel@tonic-gate 	dl_pinfo[DL_UNBIND_REQ].pi_minlen = sizeof (dl_unbind_req_t);
2680Sstevel@tonic-gate 	dl_pinfo[DL_UNBIND_REQ].pi_state = DL_IDLE;
2690Sstevel@tonic-gate 	dl_pinfo[DL_UNBIND_REQ].pi_funcp = sppp_dlunbindreq;
2700Sstevel@tonic-gate 
2710Sstevel@tonic-gate 	dl_pinfo[DL_INFO_REQ].pi_minlen = sizeof (dl_info_req_t);
272*9751Sjames.d.carlson@sun.com 	dl_pinfo[DL_INFO_REQ].pi_state = -1;	/* special handling */
2730Sstevel@tonic-gate 	dl_pinfo[DL_INFO_REQ].pi_funcp = sppp_dlinforeq;
2740Sstevel@tonic-gate 
2750Sstevel@tonic-gate 	dl_pinfo[DL_UNITDATA_REQ].pi_minlen = sizeof (dl_unitdata_req_t);
2760Sstevel@tonic-gate 	dl_pinfo[DL_UNITDATA_REQ].pi_state = DL_IDLE;
2770Sstevel@tonic-gate 	dl_pinfo[DL_UNITDATA_REQ].pi_funcp = sppp_dlunitdatareq;
2780Sstevel@tonic-gate 
2790Sstevel@tonic-gate 	dl_pinfo[DL_PROMISCON_REQ].pi_minlen = sizeof (dl_promiscon_req_t);
280*9751Sjames.d.carlson@sun.com 	dl_pinfo[DL_PROMISCON_REQ].pi_state = -1; /* special handling */
2810Sstevel@tonic-gate 	dl_pinfo[DL_PROMISCON_REQ].pi_funcp = sppp_dlpromisconreq;
2820Sstevel@tonic-gate 
2830Sstevel@tonic-gate 	dl_pinfo[DL_PROMISCOFF_REQ].pi_minlen = sizeof (dl_promiscoff_req_t);
284*9751Sjames.d.carlson@sun.com 	dl_pinfo[DL_PROMISCOFF_REQ].pi_state = -1; /* special handling */
2850Sstevel@tonic-gate 	dl_pinfo[DL_PROMISCOFF_REQ].pi_funcp = sppp_dlpromiscoffreq;
2860Sstevel@tonic-gate 
2870Sstevel@tonic-gate 	dl_pinfo[DL_PHYS_ADDR_REQ].pi_minlen = sizeof (dl_phys_addr_req_t);
288*9751Sjames.d.carlson@sun.com 	dl_pinfo[DL_PHYS_ADDR_REQ].pi_state = -1; /* special handling */
2890Sstevel@tonic-gate 	dl_pinfo[DL_PHYS_ADDR_REQ].pi_funcp = sppp_dlphyreq;
2900Sstevel@tonic-gate }
2910Sstevel@tonic-gate 
2920Sstevel@tonic-gate /*
2930Sstevel@tonic-gate  * sppp_mproto()
2940Sstevel@tonic-gate  *
2950Sstevel@tonic-gate  * MT-Perimeters:
2960Sstevel@tonic-gate  *    shared inner, shared outer.
2970Sstevel@tonic-gate  *
2980Sstevel@tonic-gate  * Description:
2990Sstevel@tonic-gate  *    Handle M_PCPROTO/M_PROTO messages, called by sppp_uwput.
3000Sstevel@tonic-gate  */
3010Sstevel@tonic-gate int
sppp_mproto(queue_t * q,mblk_t * mp,spppstr_t * sps)3020Sstevel@tonic-gate sppp_mproto(queue_t *q, mblk_t *mp, spppstr_t *sps)
3030Sstevel@tonic-gate {
3040Sstevel@tonic-gate 	union DL_primitives *dlp;
3050Sstevel@tonic-gate 	struct sppp_dlpi_pinfo_t *dpi;
3060Sstevel@tonic-gate 	t_uscalar_t	prim;
3070Sstevel@tonic-gate 	int		len;
3080Sstevel@tonic-gate 	int		error = 0;
3090Sstevel@tonic-gate 
3100Sstevel@tonic-gate 	ASSERT(!IS_SPS_CONTROL(sps));
3110Sstevel@tonic-gate 	if ((len = MBLKL(mp)) < sizeof (t_uscalar_t)) {
3120Sstevel@tonic-gate 		DBGERROR((CE_CONT, "bad mproto: block length %d\n", len));
3130Sstevel@tonic-gate 		merror(q, mp, EPROTO);
3140Sstevel@tonic-gate 		return (0);
3150Sstevel@tonic-gate 	}
3160Sstevel@tonic-gate 	dlp = (union DL_primitives *)mp->b_rptr;
3170Sstevel@tonic-gate 	prim = dlp->dl_primitive;
3180Sstevel@tonic-gate 	if (prim > DL_MAXPRIM) {
3190Sstevel@tonic-gate 		DBGERROR((CE_CONT, "bad mproto: primitive %d > %d\n", prim,
3200Sstevel@tonic-gate 		    DL_MAXPRIM));
3210Sstevel@tonic-gate 		error = DL_BADPRIM;
3220Sstevel@tonic-gate 	} else {
3230Sstevel@tonic-gate 		dpi = &dl_pinfo[prim];
3240Sstevel@tonic-gate 		if (dpi->pi_funcp == NULL) {
3250Sstevel@tonic-gate 			DBGERROR((CE_CONT,
3260Sstevel@tonic-gate 			    "bad mproto: primitive %d not supported\n", prim));
3270Sstevel@tonic-gate 			error = DL_NOTSUPPORTED;
3280Sstevel@tonic-gate 		} else if (len < dpi->pi_minlen) {
3290Sstevel@tonic-gate 			DBGERROR((CE_CONT,
3300Sstevel@tonic-gate 			    "bad mproto: primitive len %d < %d\n", len,
3310Sstevel@tonic-gate 			    dpi->pi_minlen));
3320Sstevel@tonic-gate 			error = DL_BADPRIM;
333*9751Sjames.d.carlson@sun.com 		} else if (dpi->pi_state != -1 &&
334*9751Sjames.d.carlson@sun.com 		    sps->sps_dlstate != dpi->pi_state) {
3350Sstevel@tonic-gate 			DBGERROR((CE_CONT,
3360Sstevel@tonic-gate 			    "bad state %d != %d for primitive %d\n",
3370Sstevel@tonic-gate 			    sps->sps_dlstate, dpi->pi_state, prim));
3380Sstevel@tonic-gate 			error = DL_OUTSTATE;
3390Sstevel@tonic-gate 		}
3400Sstevel@tonic-gate 	}
3410Sstevel@tonic-gate 	if (error != 0) {
3420Sstevel@tonic-gate 		dlerrorack(q, mp, dlp->dl_primitive, error, 0);
3430Sstevel@tonic-gate 		return (0);
3440Sstevel@tonic-gate 	}
3450Sstevel@tonic-gate #ifdef DBG_DLPI
3460Sstevel@tonic-gate 	{
3470Sstevel@tonic-gate 		const char *cp = prim2name(prim);
3480Sstevel@tonic-gate 		if (cp != NULL)
3490Sstevel@tonic-gate 			cmn_err(CE_CONT, "/%d: Dispatching %s\n",
3500Sstevel@tonic-gate 			    sps->sps_mn_id, cp);
3510Sstevel@tonic-gate 		else
3520Sstevel@tonic-gate 			cmn_err(CE_CONT,
3530Sstevel@tonic-gate 			    "/%d: Dispatching unknown primitive %d\n",
3540Sstevel@tonic-gate 			    sps->sps_mn_id, prim);
3550Sstevel@tonic-gate 	}
3560Sstevel@tonic-gate #endif
3570Sstevel@tonic-gate 	return ((*dpi->pi_funcp)(q, mp, sps));
3580Sstevel@tonic-gate }
3590Sstevel@tonic-gate 
3600Sstevel@tonic-gate /*
3610Sstevel@tonic-gate  * sppp_dlattachreq()
3620Sstevel@tonic-gate  *
3630Sstevel@tonic-gate  * MT-Perimeters:
3640Sstevel@tonic-gate  *    shared inner, shared outer.
3650Sstevel@tonic-gate  *
3660Sstevel@tonic-gate  * Description:
3670Sstevel@tonic-gate  *    Perform DL_ATTACH_REQ request, called by sppp_mproto.
3680Sstevel@tonic-gate  */
3690Sstevel@tonic-gate static int
sppp_dlattachreq(queue_t * q,mblk_t * mp,spppstr_t * sps)3700Sstevel@tonic-gate sppp_dlattachreq(queue_t *q, mblk_t *mp, spppstr_t *sps)
3710Sstevel@tonic-gate {
3720Sstevel@tonic-gate 	int	error = 0;
3730Sstevel@tonic-gate 	union DL_primitives *dlp;
3740Sstevel@tonic-gate 
3750Sstevel@tonic-gate 	ASSERT(q != NULL && q->q_ptr != NULL);
3760Sstevel@tonic-gate 	ASSERT(mp != NULL && mp->b_rptr != NULL);
3770Sstevel@tonic-gate 	dlp = (union DL_primitives *)mp->b_rptr;
3780Sstevel@tonic-gate 	ASSERT(sps != NULL);
3790Sstevel@tonic-gate 	ASSERT(sps->sps_dlstate == DL_UNATTACHED);
3800Sstevel@tonic-gate 
3810Sstevel@tonic-gate 	if (IS_SPS_PIOATTACH(sps)) {
3820Sstevel@tonic-gate 		DBGERROR((CE_CONT, "DLPI attach: already attached\n"));
3830Sstevel@tonic-gate 		error = EINVAL;
3840Sstevel@tonic-gate 	}
3850Sstevel@tonic-gate 	if (error != 0) {
3860Sstevel@tonic-gate 		dlerrorack(q, mp, dlp->dl_primitive, DL_OUTSTATE, error);
3870Sstevel@tonic-gate 	} else {
3880Sstevel@tonic-gate 		qwriter(q, mp, sppp_dl_attach_upper, PERIM_OUTER);
3890Sstevel@tonic-gate 	}
3900Sstevel@tonic-gate 	return (0);
3910Sstevel@tonic-gate }
3920Sstevel@tonic-gate 
3930Sstevel@tonic-gate /*
3940Sstevel@tonic-gate  * sppp_dl_attach_upper()
3950Sstevel@tonic-gate  *
3960Sstevel@tonic-gate  * MT-Perimeters:
3970Sstevel@tonic-gate  *    exclusive inner, exclusive outer.
3980Sstevel@tonic-gate  *
3990Sstevel@tonic-gate  * Description:
4000Sstevel@tonic-gate  *    Called by qwriter (INNER) from sppp_dlattachreq as the result of
4010Sstevel@tonic-gate  *    receiving a DL_ATTACH_REQ message.
4020Sstevel@tonic-gate  */
4030Sstevel@tonic-gate static void
sppp_dl_attach_upper(queue_t * q,mblk_t * mp)4040Sstevel@tonic-gate sppp_dl_attach_upper(queue_t *q, mblk_t *mp)
4050Sstevel@tonic-gate {
4060Sstevel@tonic-gate 	sppa_t		*ppa;
407*9751Sjames.d.carlson@sun.com 	spppstr_t	*sps = q->q_ptr;
4080Sstevel@tonic-gate 	union DL_primitives *dlp;
409*9751Sjames.d.carlson@sun.com 	int		err = ENOMEM;
410*9751Sjames.d.carlson@sun.com 	cred_t		*cr;
411*9751Sjames.d.carlson@sun.com 	zoneid_t	zoneid;
4120Sstevel@tonic-gate 
4130Sstevel@tonic-gate 	ASSERT(!IS_SPS_PIOATTACH(sps));
4140Sstevel@tonic-gate 	dlp = (union DL_primitives *)mp->b_rptr;
4150Sstevel@tonic-gate 
4160Sstevel@tonic-gate 	/* If there's something here, it's detached. */
4170Sstevel@tonic-gate 	if (sps->sps_ppa != NULL) {
4180Sstevel@tonic-gate 		sppp_remove_ppa(sps);
4190Sstevel@tonic-gate 	}
4200Sstevel@tonic-gate 
421*9751Sjames.d.carlson@sun.com 	if ((cr = msg_getcred(mp, NULL)) == NULL)
422*9751Sjames.d.carlson@sun.com 		zoneid = sps->sps_zoneid;
423*9751Sjames.d.carlson@sun.com 	else
424*9751Sjames.d.carlson@sun.com 		zoneid = crgetzoneid(cr);
425*9751Sjames.d.carlson@sun.com 
4260Sstevel@tonic-gate 	ppa = sppp_find_ppa(dlp->attach_req.dl_ppa);
427*9751Sjames.d.carlson@sun.com 	if (ppa == NULL) {
428*9751Sjames.d.carlson@sun.com 		ppa = sppp_create_ppa(dlp->attach_req.dl_ppa, zoneid);
429*9751Sjames.d.carlson@sun.com 	} else if (ppa->ppa_zoneid != zoneid) {
430*9751Sjames.d.carlson@sun.com 		ppa = NULL;
431*9751Sjames.d.carlson@sun.com 		err = EPERM;
432*9751Sjames.d.carlson@sun.com 	}
4330Sstevel@tonic-gate 
4340Sstevel@tonic-gate 	/*
435*9751Sjames.d.carlson@sun.com 	 * If we can't find or create it, then it's either because we're out of
436*9751Sjames.d.carlson@sun.com 	 * memory or because the requested PPA is owned by a different zone.
4370Sstevel@tonic-gate 	 */
4380Sstevel@tonic-gate 	if (ppa == NULL) {
4390Sstevel@tonic-gate 		DBGERROR((CE_CONT, "DLPI attach: cannot create ppa %u\n",
4400Sstevel@tonic-gate 		    dlp->attach_req.dl_ppa));
441*9751Sjames.d.carlson@sun.com 		dlerrorack(q, mp, dlp->dl_primitive, DL_SYSERR, err);
4420Sstevel@tonic-gate 		return;
4430Sstevel@tonic-gate 	}
4440Sstevel@tonic-gate 	/*
4450Sstevel@tonic-gate 	 * Preallocate the hangup message so that we're always able to
4460Sstevel@tonic-gate 	 * send this upstream in the event of a catastrophic failure.
4470Sstevel@tonic-gate 	 */
4480Sstevel@tonic-gate 	if ((sps->sps_hangup = allocb(1, BPRI_MED)) == NULL) {
4490Sstevel@tonic-gate 		DBGERROR((CE_CONT, "DLPI attach: cannot allocate hangup\n"));
4500Sstevel@tonic-gate 		dlerrorack(q, mp, dlp->dl_primitive, DL_SYSERR, ENOSR);
4510Sstevel@tonic-gate 		return;
4520Sstevel@tonic-gate 	}
4530Sstevel@tonic-gate 	sps->sps_dlstate = DL_UNBOUND;
4540Sstevel@tonic-gate 	sps->sps_ppa = ppa;
4550Sstevel@tonic-gate 	/*
4560Sstevel@tonic-gate 	 * Add this stream to the head of the list of sibling streams
4570Sstevel@tonic-gate 	 * which belong to the specified ppa.
4580Sstevel@tonic-gate 	 */
4590Sstevel@tonic-gate 	rw_enter(&ppa->ppa_sib_lock, RW_WRITER);
4600Sstevel@tonic-gate 	ppa->ppa_refcnt++;
4610Sstevel@tonic-gate 	sps->sps_nextsib = ppa->ppa_streams;
4620Sstevel@tonic-gate 	ppa->ppa_streams = sps;
4630Sstevel@tonic-gate 	/*
4640Sstevel@tonic-gate 	 * And if this stream was marked as promiscuous (SPS_PROMISC), then we
4650Sstevel@tonic-gate 	 * need to update the promiscuous streams count. This should only
4660Sstevel@tonic-gate 	 * happen when DL_PROMISCON_REQ was issued prior to attachment.
4670Sstevel@tonic-gate 	 */
4680Sstevel@tonic-gate 	if (IS_SPS_PROMISC(sps)) {
4690Sstevel@tonic-gate 		ppa->ppa_promicnt++;
4700Sstevel@tonic-gate 	}
4710Sstevel@tonic-gate 	rw_exit(&ppa->ppa_sib_lock);
4720Sstevel@tonic-gate 	DBGDLPI((CE_CONT, "/%d: attached to ppa %d\n", sps->sps_mn_id,
4730Sstevel@tonic-gate 	    ppa->ppa_ppa_id));
4740Sstevel@tonic-gate 	dlokack(q, mp, DL_ATTACH_REQ);
4750Sstevel@tonic-gate }
4760Sstevel@tonic-gate 
4770Sstevel@tonic-gate /*
4780Sstevel@tonic-gate  * sppp_dldetachreq()
4790Sstevel@tonic-gate  *
4800Sstevel@tonic-gate  * MT-Perimeters:
4810Sstevel@tonic-gate  *    shared inner, shared outer.
4820Sstevel@tonic-gate  *
4830Sstevel@tonic-gate  * Description:
4840Sstevel@tonic-gate  *    Perform DL_DETACH_REQ request, called by sppp_mproto.
4850Sstevel@tonic-gate  */
4860Sstevel@tonic-gate /* ARGSUSED */
4870Sstevel@tonic-gate static int
sppp_dldetachreq(queue_t * q,mblk_t * mp,spppstr_t * sps)4880Sstevel@tonic-gate sppp_dldetachreq(queue_t *q, mblk_t *mp, spppstr_t *sps)
4890Sstevel@tonic-gate {
4900Sstevel@tonic-gate 	ASSERT(q != NULL && q->q_ptr != NULL);
4910Sstevel@tonic-gate 	ASSERT(mp != NULL && mp->b_rptr != NULL);
4920Sstevel@tonic-gate 	ASSERT(sps != NULL);
4930Sstevel@tonic-gate 	ASSERT(sps->sps_dlstate == DL_UNBOUND);
4940Sstevel@tonic-gate 	ASSERT(!IS_SPS_PIOATTACH(sps));
4950Sstevel@tonic-gate 
4960Sstevel@tonic-gate 	qwriter(q, mp, sppp_dl_detach_upper, PERIM_INNER);
4970Sstevel@tonic-gate 	return (0);
4980Sstevel@tonic-gate }
4990Sstevel@tonic-gate 
5000Sstevel@tonic-gate /*
5010Sstevel@tonic-gate  * sppp_dl_detach_upper()
5020Sstevel@tonic-gate  *
5030Sstevel@tonic-gate  * MT-Perimeters:
5040Sstevel@tonic-gate  *    exclusive inner, shared outer.
5050Sstevel@tonic-gate  *
5060Sstevel@tonic-gate  * Description:
5070Sstevel@tonic-gate  *    Called by qwriter (INNER) from sppp_dldetachreq as the result of
5080Sstevel@tonic-gate  *    receiving a DL_DETACH_REQ message.
5090Sstevel@tonic-gate  */
5100Sstevel@tonic-gate /* ARGSUSED */
5110Sstevel@tonic-gate static void
sppp_dl_detach_upper(queue_t * q,mblk_t * mp)5120Sstevel@tonic-gate sppp_dl_detach_upper(queue_t *q, mblk_t *mp)
5130Sstevel@tonic-gate {
5140Sstevel@tonic-gate 	spppstr_t	*sps;
5150Sstevel@tonic-gate 
5160Sstevel@tonic-gate 	ASSERT(q != NULL && q->q_ptr != NULL);
5170Sstevel@tonic-gate 	ASSERT(mp != NULL && mp->b_rptr != NULL);
5180Sstevel@tonic-gate 	sps = (spppstr_t *)q->q_ptr;
5190Sstevel@tonic-gate 	/*
5200Sstevel@tonic-gate 	 * We don't actually detach from the PPA until closed or
5210Sstevel@tonic-gate 	 * reattached.
5220Sstevel@tonic-gate 	 */
5230Sstevel@tonic-gate 	sps->sps_flags &= ~SPS_PROMISC;	/* clear flag anyway */
5240Sstevel@tonic-gate 	sps->sps_dlstate = DL_UNATTACHED;
5250Sstevel@tonic-gate 	dlokack(q, mp, DL_DETACH_REQ);
5260Sstevel@tonic-gate }
5270Sstevel@tonic-gate 
5280Sstevel@tonic-gate /*
5290Sstevel@tonic-gate  * sppp_dlbindreq()
5300Sstevel@tonic-gate  *
5310Sstevel@tonic-gate  * MT-Perimeters:
5320Sstevel@tonic-gate  *    shared inner, shared outer.
5330Sstevel@tonic-gate  *
5340Sstevel@tonic-gate  * Description:
5350Sstevel@tonic-gate  *    Perform DL_BIND_REQ request, called by sppp_mproto.
5360Sstevel@tonic-gate  */
5370Sstevel@tonic-gate static int
sppp_dlbindreq(queue_t * q,mblk_t * mp,spppstr_t * sps)5380Sstevel@tonic-gate sppp_dlbindreq(queue_t *q, mblk_t *mp, spppstr_t *sps)
5390Sstevel@tonic-gate {
5400Sstevel@tonic-gate 	sppa_t			*ppa;
5410Sstevel@tonic-gate 	union DL_primitives	*dlp;
5420Sstevel@tonic-gate 	spppreqsap_t		req_sap;
5430Sstevel@tonic-gate 	int			error = 0;
5440Sstevel@tonic-gate 
5450Sstevel@tonic-gate 	ASSERT(q != NULL && q->q_ptr != NULL);
5460Sstevel@tonic-gate 	ASSERT(mp != NULL && mp->b_rptr != NULL);
5470Sstevel@tonic-gate 	dlp = (union DL_primitives *)mp->b_rptr;
5480Sstevel@tonic-gate 	req_sap = dlp->bind_req.dl_sap;
5490Sstevel@tonic-gate 	ASSERT(sps != NULL);
5500Sstevel@tonic-gate 	ASSERT(!IS_SPS_PIOATTACH(sps));
5510Sstevel@tonic-gate 	ASSERT(sps->sps_dlstate == DL_UNBOUND);
5520Sstevel@tonic-gate 
5530Sstevel@tonic-gate 	ppa = sps->sps_ppa;
5540Sstevel@tonic-gate 	if (ppa == NULL) {
5550Sstevel@tonic-gate 		DBGERROR((CE_CONT, "DLPI bind: no attached ppa\n"));
5560Sstevel@tonic-gate 		error = DL_OUTSTATE;
5570Sstevel@tonic-gate 	} else if ((req_sap != ETHERTYPE_IP) && (req_sap != ETHERTYPE_IPV6) &&
558*9751Sjames.d.carlson@sun.com 	    (req_sap != ETHERTYPE_ALLSAP)) {
5590Sstevel@tonic-gate 		DBGERROR((CE_CONT, "DLPI bind: unknown SAP %x\n", req_sap));
5600Sstevel@tonic-gate 		error = DL_BADADDR;
5610Sstevel@tonic-gate 	}
5620Sstevel@tonic-gate 	if (error != 0) {
5630Sstevel@tonic-gate 		dlerrorack(q, mp, dlp->dl_primitive, error, 0);
5640Sstevel@tonic-gate 	} else {
5650Sstevel@tonic-gate 		qwriter(q, mp, sppp_dl_bind, PERIM_INNER);
5660Sstevel@tonic-gate 	}
5670Sstevel@tonic-gate 	return (0);
5680Sstevel@tonic-gate }
5690Sstevel@tonic-gate 
5700Sstevel@tonic-gate /*
5710Sstevel@tonic-gate  * sppp_dl_bind()
5720Sstevel@tonic-gate  *
5730Sstevel@tonic-gate  * MT-Perimeters:
5740Sstevel@tonic-gate  *    exclusive inner, shared outer.
5750Sstevel@tonic-gate  *
5760Sstevel@tonic-gate  * Description:
5770Sstevel@tonic-gate  *    Called by qwriter (INNER) from sppp_dlbindreq as the result of
5780Sstevel@tonic-gate  *    receiving a DL_BIND_REQ message.
5790Sstevel@tonic-gate  */
5800Sstevel@tonic-gate static void
sppp_dl_bind(queue_t * q,mblk_t * mp)5810Sstevel@tonic-gate sppp_dl_bind(queue_t *q, mblk_t *mp)
5820Sstevel@tonic-gate {
5830Sstevel@tonic-gate 	spppstr_t		*sps;
5840Sstevel@tonic-gate 	sppa_t			*ppa;
5850Sstevel@tonic-gate 	union DL_primitives	*dlp;
5860Sstevel@tonic-gate 	t_scalar_t		sap;
5870Sstevel@tonic-gate 	spppreqsap_t		req_sap;
5880Sstevel@tonic-gate 	mblk_t			*lsmp;
5890Sstevel@tonic-gate 
5900Sstevel@tonic-gate 	ASSERT(q != NULL && q->q_ptr != NULL);
5910Sstevel@tonic-gate 	sps = (spppstr_t *)q->q_ptr;
5920Sstevel@tonic-gate 	ASSERT(mp != NULL && mp->b_rptr != NULL);
5930Sstevel@tonic-gate 	dlp = (union DL_primitives *)mp->b_rptr;
5940Sstevel@tonic-gate 	ppa = sps->sps_ppa;
5950Sstevel@tonic-gate 	ASSERT(ppa != NULL);
5960Sstevel@tonic-gate 	req_sap = dlp->bind_req.dl_sap;
5970Sstevel@tonic-gate 	ASSERT((req_sap == ETHERTYPE_IP) || (req_sap == ETHERTYPE_IPV6) ||
598*9751Sjames.d.carlson@sun.com 	    (req_sap == ETHERTYPE_ALLSAP));
5990Sstevel@tonic-gate 
6000Sstevel@tonic-gate 	if (req_sap == ETHERTYPE_IP) {
6010Sstevel@tonic-gate 		sap = PPP_IP;
6020Sstevel@tonic-gate 	} else if (req_sap == ETHERTYPE_IPV6) {
6030Sstevel@tonic-gate 		sap = PPP_IPV6;
6040Sstevel@tonic-gate 	} else if (req_sap == ETHERTYPE_ALLSAP) {
6050Sstevel@tonic-gate 		sap = PPP_ALLSAP;
6060Sstevel@tonic-gate 	}
6070Sstevel@tonic-gate 	/*
6080Sstevel@tonic-gate 	 * If there's another stream with the same sap has already been bound
6090Sstevel@tonic-gate 	 * to the same ppa, then return with DL_NOADDR. However, we do make an
6100Sstevel@tonic-gate 	 * exception for snoop (req_sap=0x00, sap=0xff) since multiple
6110Sstevel@tonic-gate 	 * instances of snoop may execute an a given device.
6120Sstevel@tonic-gate 	 */
6130Sstevel@tonic-gate 	lsmp = NULL;
6140Sstevel@tonic-gate 	if (sap != PPP_ALLSAP) {
6150Sstevel@tonic-gate 		if ((sap == PPP_IP) && (ppa->ppa_ip_cache == NULL)) {
6160Sstevel@tonic-gate 			ppa->ppa_ip_cache = sps;
6170Sstevel@tonic-gate 			if (ppa->ppa_ctl != NULL) {
6180Sstevel@tonic-gate 				lsmp = create_lsmsg(PPP_LINKSTAT_IPV4_BOUND);
6190Sstevel@tonic-gate 			}
6200Sstevel@tonic-gate 		} else if ((sap == PPP_IPV6) && (ppa->ppa_ip6_cache == NULL)) {
6210Sstevel@tonic-gate 			ppa->ppa_ip6_cache = sps;
6220Sstevel@tonic-gate 			if (ppa->ppa_ctl != NULL) {
6230Sstevel@tonic-gate 				lsmp = create_lsmsg(PPP_LINKSTAT_IPV6_BOUND);
6240Sstevel@tonic-gate 			}
6250Sstevel@tonic-gate 		} else {
6260Sstevel@tonic-gate 			DBGERROR((CE_CONT, "DLPI bind: bad SAP %x\n", sap));
6270Sstevel@tonic-gate 			dlerrorack(q, mp, dlp->dl_primitive, DL_NOADDR,
6280Sstevel@tonic-gate 			    EEXIST);
6290Sstevel@tonic-gate 			return;
6300Sstevel@tonic-gate 		}
6310Sstevel@tonic-gate 		sps->sps_flags |= SPS_CACHED;
6320Sstevel@tonic-gate 	}
6330Sstevel@tonic-gate 	/*
6340Sstevel@tonic-gate 	 * Tell the daemon that a DLPI bind has happened on this stream,
6350Sstevel@tonic-gate 	 * and we'll only do this for PPP_IP or PPP_IPV6 sap (not snoop).
6360Sstevel@tonic-gate 	 */
6370Sstevel@tonic-gate 	if (lsmp != NULL && ppa->ppa_ctl != NULL) {
6380Sstevel@tonic-gate #ifdef DBG_DLPI
6390Sstevel@tonic-gate 		cmn_err(CE_CONT, "sending up %s\n",
6400Sstevel@tonic-gate 		    ((sap == PPP_IP) ? "PPP_LINKSTAT_IPV4_BOUND" :
6410Sstevel@tonic-gate 		    "PPP_LINKSTAT_IPV6_BOUND"));
6420Sstevel@tonic-gate #endif
6430Sstevel@tonic-gate 		putnext(ppa->ppa_ctl->sps_rq, lsmp);
6440Sstevel@tonic-gate 	}
6450Sstevel@tonic-gate 	DBGDLPI((CE_CONT, "/%d: bound to sap %X (req %X)\n", sps->sps_mn_id,
6460Sstevel@tonic-gate 	    sap, req_sap));
6470Sstevel@tonic-gate 	sps->sps_req_sap = req_sap;
6480Sstevel@tonic-gate 	sps->sps_sap = sap;
6490Sstevel@tonic-gate 	sps->sps_dlstate = DL_IDLE;
6500Sstevel@tonic-gate 	dlbindack(q, mp, req_sap, &sap, sizeof (int32_t), 0, 0);
6510Sstevel@tonic-gate }
6520Sstevel@tonic-gate 
6530Sstevel@tonic-gate /*
6540Sstevel@tonic-gate  * sppp_dlunbindreq()
6550Sstevel@tonic-gate  *
6560Sstevel@tonic-gate  * MT-Perimeters:
6570Sstevel@tonic-gate  *    shared inner, shared outer.
6580Sstevel@tonic-gate  *
6590Sstevel@tonic-gate  * Description:
6600Sstevel@tonic-gate  *    Perform DL_UNBIND_REQ request, called by sppp_mproto.
6610Sstevel@tonic-gate  */
6620Sstevel@tonic-gate /* ARGSUSED */
6630Sstevel@tonic-gate static int
sppp_dlunbindreq(queue_t * q,mblk_t * mp,spppstr_t * sps)6640Sstevel@tonic-gate sppp_dlunbindreq(queue_t *q, mblk_t *mp, spppstr_t *sps)
6650Sstevel@tonic-gate {
6660Sstevel@tonic-gate 	ASSERT(q != NULL && q->q_ptr != NULL);
6670Sstevel@tonic-gate 	ASSERT(mp != NULL && mp->b_rptr != NULL);
6680Sstevel@tonic-gate 	ASSERT(sps != NULL);
6690Sstevel@tonic-gate 	ASSERT(!IS_SPS_PIOATTACH(sps));
6700Sstevel@tonic-gate 	ASSERT(sps->sps_dlstate == DL_IDLE);
6710Sstevel@tonic-gate 
6720Sstevel@tonic-gate 	qwriter(q, mp, sppp_dl_unbind, PERIM_INNER);
6730Sstevel@tonic-gate 	return (0);
6740Sstevel@tonic-gate }
6750Sstevel@tonic-gate 
6760Sstevel@tonic-gate /*
6770Sstevel@tonic-gate  * sppp_dl_unbind()
6780Sstevel@tonic-gate  *
6790Sstevel@tonic-gate  * MT-Perimeters:
6800Sstevel@tonic-gate  *    exclusive inner, shared outer.
6810Sstevel@tonic-gate  *
6820Sstevel@tonic-gate  * Description:
6830Sstevel@tonic-gate  *    Called by qwriter (INNER) from sppp_dlunbindreq as the result of
6840Sstevel@tonic-gate  *    receiving a DL_UNBIND_REQ message.
6850Sstevel@tonic-gate  */
6860Sstevel@tonic-gate static void
sppp_dl_unbind(queue_t * q,mblk_t * mp)6870Sstevel@tonic-gate sppp_dl_unbind(queue_t *q, mblk_t *mp)
6880Sstevel@tonic-gate {
6890Sstevel@tonic-gate 	spppstr_t	*sps;
6900Sstevel@tonic-gate 	sppa_t		*ppa;
6910Sstevel@tonic-gate 	t_scalar_t	sap;
6920Sstevel@tonic-gate 	mblk_t		*msg;
6930Sstevel@tonic-gate 	boolean_t	saydown;
6940Sstevel@tonic-gate 
6950Sstevel@tonic-gate 	ASSERT(q != NULL && q->q_ptr != NULL);
6960Sstevel@tonic-gate 	sps = (spppstr_t *)q->q_ptr;
6970Sstevel@tonic-gate 	ppa = sps->sps_ppa;
6980Sstevel@tonic-gate 	ASSERT(mp != NULL && mp->b_rptr != NULL);
6990Sstevel@tonic-gate 	sap = sps->sps_sap;
7000Sstevel@tonic-gate 	ASSERT((sap == PPP_IP) || (sap == PPP_IPV6) || (sap == PPP_ALLSAP));
7010Sstevel@tonic-gate 
7020Sstevel@tonic-gate 	/* Flush messages on unbind, per DLPI specification. */
7030Sstevel@tonic-gate 	flushq(WR(q), FLUSHALL);
7040Sstevel@tonic-gate 	flushq(RD(q), FLUSHALL);
7050Sstevel@tonic-gate 
7060Sstevel@tonic-gate 	if ((ppa != NULL) && IS_SPS_CACHED(sps)) {
7070Sstevel@tonic-gate 		sps->sps_flags &= ~SPS_CACHED;
7080Sstevel@tonic-gate 		msg = NULL;
7090Sstevel@tonic-gate 		saydown = (ppa->ppa_ctl != NULL &&
7100Sstevel@tonic-gate 		    (sps->sps_npmode == NPMODE_PASS ||
711*9751Sjames.d.carlson@sun.com 		    sps->sps_npmode == NPMODE_QUEUE));
7120Sstevel@tonic-gate 		if (sap == PPP_IP) {
7130Sstevel@tonic-gate 			ppa->ppa_ip_cache = NULL;
7140Sstevel@tonic-gate 			if (saydown)
7150Sstevel@tonic-gate 				msg = create_lsmsg(PPP_LINKSTAT_IPV4_UNBOUND);
7160Sstevel@tonic-gate 		} else if (sap == PPP_IPV6) {
7170Sstevel@tonic-gate 			ppa->ppa_ip6_cache = NULL;
7180Sstevel@tonic-gate 			if (saydown)
7190Sstevel@tonic-gate 				msg = create_lsmsg(PPP_LINKSTAT_IPV6_UNBOUND);
7200Sstevel@tonic-gate 		}
7210Sstevel@tonic-gate 		if (msg != NULL) {
7220Sstevel@tonic-gate #ifdef DBG_DLPI
7230Sstevel@tonic-gate 			cmn_err(CE_CONT, "sending up %s\n",
7240Sstevel@tonic-gate 			    ((sap == PPP_IP) ? "PPP_LINKSTAT_IPV4_UNBOUND" :
7250Sstevel@tonic-gate 			    "PPP_LINKSTAT_IPV6_UNBOUND"));
7260Sstevel@tonic-gate #endif
7270Sstevel@tonic-gate 			putnext(ppa->ppa_ctl->sps_rq, msg);
7280Sstevel@tonic-gate 		}
7290Sstevel@tonic-gate 	}
7300Sstevel@tonic-gate 	DBGDLPI((CE_CONT, "/%d: unbound from sap %X (req %X)\n", sps->sps_mn_id,
7310Sstevel@tonic-gate 	    sps->sps_sap, sps->sps_req_sap));
7320Sstevel@tonic-gate 	sps->sps_req_sap = 0;
7330Sstevel@tonic-gate 	sps->sps_sap = -1;
7340Sstevel@tonic-gate 	sps->sps_dlstate = DL_UNBOUND;
7350Sstevel@tonic-gate 
7360Sstevel@tonic-gate 	dlokack(q, mp, DL_UNBIND_REQ);
7370Sstevel@tonic-gate }
7380Sstevel@tonic-gate 
7390Sstevel@tonic-gate /*
7400Sstevel@tonic-gate  * sppp_dlinforeq()
7410Sstevel@tonic-gate  *
7420Sstevel@tonic-gate  * MT-Perimeters:
7430Sstevel@tonic-gate  *    shared inner, shared outer.
7440Sstevel@tonic-gate  *
7450Sstevel@tonic-gate  * Description:
7460Sstevel@tonic-gate  *    Perform DL_INFO_REQ request, called by sppp_mproto.
7470Sstevel@tonic-gate  */
7480Sstevel@tonic-gate static int
sppp_dlinforeq(queue_t * q,mblk_t * mp,spppstr_t * sps)7490Sstevel@tonic-gate sppp_dlinforeq(queue_t *q, mblk_t *mp, spppstr_t *sps)
7500Sstevel@tonic-gate {
7510Sstevel@tonic-gate 	dl_info_ack_t	*dlip;
7520Sstevel@tonic-gate 	uint32_t	size;
7530Sstevel@tonic-gate 	uint32_t	addr_size;
7540Sstevel@tonic-gate 	sppa_t		*ppa;
7550Sstevel@tonic-gate 
7560Sstevel@tonic-gate 	ASSERT(q != NULL && q->q_ptr != NULL);
7570Sstevel@tonic-gate 	ASSERT(mp != NULL && mp->b_rptr != NULL);
7580Sstevel@tonic-gate 	ASSERT(sps != NULL);
7590Sstevel@tonic-gate 	ppa = sps->sps_ppa;
7600Sstevel@tonic-gate 
7610Sstevel@tonic-gate 	/* Exchange current msg for a DL_INFO_ACK. */
7620Sstevel@tonic-gate 	addr_size = SPPP_ADDRL;
7630Sstevel@tonic-gate 	size = sizeof (dl_info_ack_t) + addr_size;
7640Sstevel@tonic-gate 	if ((mp = mexchange(q, mp, size, M_PCPROTO, DL_INFO_ACK)) == NULL) {
7650Sstevel@tonic-gate 		DBGERROR((CE_CONT, "DLPI info: mexchange failed\n"));
7660Sstevel@tonic-gate 		/* mexchange already sent up an merror ENOSR */
7670Sstevel@tonic-gate 		return (0);
7680Sstevel@tonic-gate 	}
7690Sstevel@tonic-gate 	/* Fill in DL_INFO_ACK fields and reply */
7700Sstevel@tonic-gate 	dlip = (dl_info_ack_t *)mp->b_rptr;
7710Sstevel@tonic-gate 	*dlip = sppp_infoack;
7720Sstevel@tonic-gate 	dlip->dl_current_state = sps->sps_dlstate;
7730Sstevel@tonic-gate 	dlip->dl_max_sdu = ppa != NULL ? ppa->ppa_mtu : PPP_MAXMTU;
7740Sstevel@tonic-gate #ifdef DBG_DLPI
7750Sstevel@tonic-gate 	{
7760Sstevel@tonic-gate 		const char *cp = state2name(dlip->dl_current_state);
7770Sstevel@tonic-gate 		if (cp != NULL)
7780Sstevel@tonic-gate 			cmn_err(CE_CONT, "info returns state %s, max sdu %d\n",
7790Sstevel@tonic-gate 			    cp, dlip->dl_max_sdu);
7800Sstevel@tonic-gate 		else
7810Sstevel@tonic-gate 			cmn_err(CE_CONT, "info returns state %d, max sdu %d\n",
7820Sstevel@tonic-gate 			    dlip->dl_current_state, dlip->dl_max_sdu);
7830Sstevel@tonic-gate 	}
7840Sstevel@tonic-gate #endif
7850Sstevel@tonic-gate 	qreply(q, mp);
7860Sstevel@tonic-gate 	return (0);
7870Sstevel@tonic-gate }
7880Sstevel@tonic-gate 
7890Sstevel@tonic-gate /*
7900Sstevel@tonic-gate  * sppp_dlunitdatareq()
7910Sstevel@tonic-gate  *
7920Sstevel@tonic-gate  * MT-Perimeters:
7930Sstevel@tonic-gate  *    shared inner, shared outer.
7940Sstevel@tonic-gate  *
7950Sstevel@tonic-gate  * Description:
7960Sstevel@tonic-gate  *    Handle DL_UNITDATA_REQ request, called by sppp_mproto. This procedure
7970Sstevel@tonic-gate  *    gets called for M_PROTO (DLPI) style of transmission. The fact that we
7980Sstevel@tonic-gate  *    have acknowledged IP's fastpath probing (DL_IOC_HDR_INFO) does not
7990Sstevel@tonic-gate  *    guarantee that IP will always transmit via M_DATA, and it merely implies
8000Sstevel@tonic-gate  *    that such situation _may_ happen. In other words, IP may decide to use
8010Sstevel@tonic-gate  *    M_PROTO (DLPI) for data transmission should it decide to do so.
8020Sstevel@tonic-gate  *    Therefore, we should never place any restrictions or checks against
8030Sstevel@tonic-gate  *    streams marked with SPS_FASTPATH, since it is legal for this procedure
8040Sstevel@tonic-gate  *    to be entered with or without the bit set.
8050Sstevel@tonic-gate  */
8060Sstevel@tonic-gate static int
sppp_dlunitdatareq(queue_t * q,mblk_t * mp,spppstr_t * sps)8070Sstevel@tonic-gate sppp_dlunitdatareq(queue_t *q, mblk_t *mp, spppstr_t *sps)
8080Sstevel@tonic-gate {
8090Sstevel@tonic-gate 	sppa_t		*ppa;
8100Sstevel@tonic-gate 	mblk_t		*hdrmp;
8110Sstevel@tonic-gate 	mblk_t		*pktmp;
8120Sstevel@tonic-gate 	dl_unitdata_req_t *dludp;
8130Sstevel@tonic-gate 	int		dladdroff;
8140Sstevel@tonic-gate 	int		dladdrlen;
8150Sstevel@tonic-gate 	int		msize;
8160Sstevel@tonic-gate 	int		error = 0;
8170Sstevel@tonic-gate 	boolean_t	is_promisc;
8180Sstevel@tonic-gate 
8190Sstevel@tonic-gate 	ASSERT(q != NULL && q->q_ptr != NULL);
8200Sstevel@tonic-gate 	ASSERT(mp != NULL && mp->b_rptr != NULL);
8210Sstevel@tonic-gate 	ASSERT((MTYPE(mp) == M_PCPROTO) || (MTYPE(mp) == M_PROTO));
8220Sstevel@tonic-gate 	dludp = (dl_unitdata_req_t *)mp->b_rptr;
8230Sstevel@tonic-gate 	dladdroff = dludp->dl_dest_addr_offset;
8240Sstevel@tonic-gate 	dladdrlen = dludp->dl_dest_addr_length;
8250Sstevel@tonic-gate 	ASSERT(sps != NULL);
8260Sstevel@tonic-gate 	ASSERT(!IS_SPS_PIOATTACH(sps));
8270Sstevel@tonic-gate 	ASSERT(sps->sps_dlstate == DL_IDLE);
8280Sstevel@tonic-gate 	ASSERT(q->q_ptr == sps);
8290Sstevel@tonic-gate 	/*
8300Sstevel@tonic-gate 	 * If this stream is not attached to any ppas, then discard data
8310Sstevel@tonic-gate 	 * coming down through this stream.
8320Sstevel@tonic-gate 	 */
8330Sstevel@tonic-gate 	ppa = sps->sps_ppa;
8340Sstevel@tonic-gate 	if (ppa == NULL) {
8350Sstevel@tonic-gate 		DBGERROR((CE_CONT, "DLPI unitdata: no attached ppa\n"));
8360Sstevel@tonic-gate 		error = ENOLINK;
8370Sstevel@tonic-gate 	} else if (mp->b_cont == NULL) {
8380Sstevel@tonic-gate 		DBGERROR((CE_CONT, "DLPI unitdata: missing data\n"));
8390Sstevel@tonic-gate 		error = EPROTO;
8400Sstevel@tonic-gate 	}
8410Sstevel@tonic-gate 	if (error != 0) {
8420Sstevel@tonic-gate 		dluderrorind(q, mp, mp->b_rptr + dladdroff, dladdrlen,
8430Sstevel@tonic-gate 		    DL_BADDATA, error);
8440Sstevel@tonic-gate 		return (0);
8450Sstevel@tonic-gate 	}
8460Sstevel@tonic-gate 	ASSERT(mp->b_cont->b_rptr != NULL);
8470Sstevel@tonic-gate 	/*
8480Sstevel@tonic-gate 	 * Check if outgoing packet size is larger than allowed. We use
8490Sstevel@tonic-gate 	 * msgdsize to count all of M_DATA blocks in the message.
8500Sstevel@tonic-gate 	 */
8510Sstevel@tonic-gate 	msize = msgdsize(mp);
8520Sstevel@tonic-gate 	if (msize > ppa->ppa_mtu) {
8530Sstevel@tonic-gate 		/* Log, and send it anyway */
8540Sstevel@tonic-gate 		mutex_enter(&ppa->ppa_sta_lock);
8550Sstevel@tonic-gate 		ppa->ppa_otoolongs++;
8560Sstevel@tonic-gate 		mutex_exit(&ppa->ppa_sta_lock);
8570Sstevel@tonic-gate 	}
8580Sstevel@tonic-gate 	if (IS_SPS_KDEBUG(sps)) {
8590Sstevel@tonic-gate 		SPDEBUG(PPP_DRV_NAME
8600Sstevel@tonic-gate 		    "/%d: DL_UNITDATA_REQ (%d bytes) sps=0x%p flags=0x%b "
8610Sstevel@tonic-gate 		    "ppa=0x%p flags=0x%b\n", sps->sps_mn_id, msize,
8620Sstevel@tonic-gate 		    (void *)sps, sps->sps_flags, SPS_FLAGS_STR,
8630Sstevel@tonic-gate 		    (void *)ppa, ppa->ppa_flags, PPA_FLAGS_STR);
8640Sstevel@tonic-gate 	}
8650Sstevel@tonic-gate 	/* Allocate a message (M_DATA) to contain PPP header bytes. */
8660Sstevel@tonic-gate 	if ((hdrmp = allocb(PPP_HDRLEN, BPRI_MED)) == NULL) {
8670Sstevel@tonic-gate 		mutex_enter(&ppa->ppa_sta_lock);
8680Sstevel@tonic-gate 		ppa->ppa_allocbfail++;
8690Sstevel@tonic-gate 		mutex_exit(&ppa->ppa_sta_lock);
8700Sstevel@tonic-gate 		DBGERROR((CE_CONT,
8710Sstevel@tonic-gate 		    "DLPI unitdata: can't allocate header buffer\n"));
8720Sstevel@tonic-gate 		dluderrorind(q, mp, mp->b_rptr + dladdroff, dladdrlen,
8730Sstevel@tonic-gate 		    DL_SYSERR, ENOSR);
8740Sstevel@tonic-gate 		return (0);
8750Sstevel@tonic-gate 	}
8760Sstevel@tonic-gate 	/*
8770Sstevel@tonic-gate 	 * Should there be any promiscuous stream(s), send the data up
8780Sstevel@tonic-gate 	 * for each promiscuous stream that we recognize.
8790Sstevel@tonic-gate 	 */
8800Sstevel@tonic-gate 	rw_enter(&ppa->ppa_sib_lock, RW_READER);
8810Sstevel@tonic-gate 	is_promisc = ppa->ppa_promicnt;
8820Sstevel@tonic-gate 	if (is_promisc) {
8830Sstevel@tonic-gate 		ASSERT(ppa->ppa_streams != NULL);
8840Sstevel@tonic-gate 		sppp_dlprsendup(ppa->ppa_streams, mp->b_cont, sps->sps_sap,
8850Sstevel@tonic-gate 		    B_FALSE);
8860Sstevel@tonic-gate 	}
8870Sstevel@tonic-gate 	rw_exit(&ppa->ppa_sib_lock);
8880Sstevel@tonic-gate 	/* Discard DLPI header and keep only IP payload (mp->b_cont). */
8890Sstevel@tonic-gate 	pktmp = mp->b_cont;
8900Sstevel@tonic-gate 	mp->b_cont = NULL;
8910Sstevel@tonic-gate 	freemsg(mp);
8920Sstevel@tonic-gate 	mp = hdrmp;
8930Sstevel@tonic-gate 
8940Sstevel@tonic-gate 	*(uchar_t *)mp->b_wptr++ = PPP_ALLSTATIONS;
8950Sstevel@tonic-gate 	*(uchar_t *)mp->b_wptr++ = PPP_UI;
8960Sstevel@tonic-gate 	*(uchar_t *)mp->b_wptr++ = ((uint16_t)sps->sps_sap >> 8) & 0xff;
8970Sstevel@tonic-gate 	*(uchar_t *)mp->b_wptr++ = ((uint16_t)sps->sps_sap) & 0xff;
8980Sstevel@tonic-gate 	ASSERT(MBLKL(mp) == PPP_HDRLEN);
8990Sstevel@tonic-gate 
9000Sstevel@tonic-gate 	linkb(mp, pktmp);
9010Sstevel@tonic-gate 	/*
9020Sstevel@tonic-gate 	 * Only time-stamp the packet with hrtime if the upper stream
9030Sstevel@tonic-gate 	 * is configured to do so.
9040Sstevel@tonic-gate 	 */
9050Sstevel@tonic-gate 	if (IS_PPA_TIMESTAMP(ppa)) {
9060Sstevel@tonic-gate 		ppa->ppa_lasttx = gethrtime();
9070Sstevel@tonic-gate 	}
9080Sstevel@tonic-gate 	/*
9090Sstevel@tonic-gate 	 * Just put this back on the queue and allow the write service
9100Sstevel@tonic-gate 	 * routine to handle it.  We're nested too deeply here to
9110Sstevel@tonic-gate 	 * rewind the stack sufficiently to prevent overflow.  This is
9120Sstevel@tonic-gate 	 * the slow path anyway.
9130Sstevel@tonic-gate 	 */
9140Sstevel@tonic-gate 	if (putq(q, mp) == 0) {
9150Sstevel@tonic-gate 		mutex_enter(&ppa->ppa_sta_lock);
9160Sstevel@tonic-gate 		ppa->ppa_oqdropped++;
9170Sstevel@tonic-gate 		mutex_exit(&ppa->ppa_sta_lock);
9180Sstevel@tonic-gate 		freemsg(mp);
9190Sstevel@tonic-gate 	} else {
9200Sstevel@tonic-gate 		qenable(q);
9210Sstevel@tonic-gate 	}
9220Sstevel@tonic-gate 	return (0);
9230Sstevel@tonic-gate }
9240Sstevel@tonic-gate 
9250Sstevel@tonic-gate /*
9260Sstevel@tonic-gate  * sppp_dlpromisconreq()
9270Sstevel@tonic-gate  *
9280Sstevel@tonic-gate  * MT-Perimeters:
9290Sstevel@tonic-gate  *    shared inner, shared outer.
9300Sstevel@tonic-gate  *
9310Sstevel@tonic-gate  * Description:
9320Sstevel@tonic-gate  *    Perform DL_PROMISCON_REQ request, called by sppp_mproto.
9330Sstevel@tonic-gate  */
9340Sstevel@tonic-gate static int
sppp_dlpromisconreq(queue_t * q,mblk_t * mp,spppstr_t * sps)9350Sstevel@tonic-gate sppp_dlpromisconreq(queue_t *q, mblk_t *mp, spppstr_t *sps)
9360Sstevel@tonic-gate {
9370Sstevel@tonic-gate 	t_uscalar_t	level;
9380Sstevel@tonic-gate 
9390Sstevel@tonic-gate 	ASSERT(q != NULL && q->q_ptr != NULL);
9400Sstevel@tonic-gate 	ASSERT(mp != NULL && mp->b_rptr != NULL);
9410Sstevel@tonic-gate 	level = ((dl_promiscon_req_t *)mp->b_rptr)->dl_level;
9420Sstevel@tonic-gate 	ASSERT(sps != NULL);
9430Sstevel@tonic-gate 
9440Sstevel@tonic-gate 	/* snoop issues DL_PROMISCON_REQ more than once. */
9450Sstevel@tonic-gate 	if (IS_SPS_PROMISC(sps)) {
9460Sstevel@tonic-gate 		dlokack(q, mp, DL_PROMISCON_REQ);
9470Sstevel@tonic-gate 	} else if ((level != DL_PROMISC_PHYS) && (level != DL_PROMISC_SAP) &&
9480Sstevel@tonic-gate 	    (level != DL_PROMISC_MULTI)) {
9490Sstevel@tonic-gate 		DBGERROR((CE_CONT, "DLPI promiscon: bad level %d\n", level));
9500Sstevel@tonic-gate 		dlerrorack(q, mp, DL_PROMISCON_REQ, DL_NOTSUPPORTED, 0);
9510Sstevel@tonic-gate 	} else {
9520Sstevel@tonic-gate 		qwriter(q, mp, sppp_dl_promiscon, PERIM_INNER);
9530Sstevel@tonic-gate 	}
9540Sstevel@tonic-gate 	return (0);
9550Sstevel@tonic-gate }
9560Sstevel@tonic-gate 
9570Sstevel@tonic-gate /*
9580Sstevel@tonic-gate  * sppp_dl_promiscon()
9590Sstevel@tonic-gate  *
9600Sstevel@tonic-gate  * MT-Perimeters:
9610Sstevel@tonic-gate  *    exclusive inner, shared outer.
9620Sstevel@tonic-gate  *
9630Sstevel@tonic-gate  * Description:
9640Sstevel@tonic-gate  *    Called by qwriter (INNER) from sppp_dlpromisconreq as the result of
9650Sstevel@tonic-gate  *    receiving a DL_PROMISCON_REQ message.
9660Sstevel@tonic-gate  */
9670Sstevel@tonic-gate static void
sppp_dl_promiscon(queue_t * q,mblk_t * mp)9680Sstevel@tonic-gate sppp_dl_promiscon(queue_t *q, mblk_t *mp)
9690Sstevel@tonic-gate {
9700Sstevel@tonic-gate 	spppstr_t	*sps;
9710Sstevel@tonic-gate 	sppa_t		*ppa;
9720Sstevel@tonic-gate 
9730Sstevel@tonic-gate 	ASSERT(q != NULL && q->q_ptr != NULL);
9740Sstevel@tonic-gate 	sps = (spppstr_t *)q->q_ptr;
9750Sstevel@tonic-gate 	ASSERT(!IS_SPS_PROMISC(sps));
9760Sstevel@tonic-gate 	ASSERT(mp != NULL && mp->b_rptr != NULL);
9770Sstevel@tonic-gate 	ppa = sps->sps_ppa;
9780Sstevel@tonic-gate 
9790Sstevel@tonic-gate 	sps->sps_flags |= SPS_PROMISC;
9800Sstevel@tonic-gate 	/*
9810Sstevel@tonic-gate 	 * We can't be sure that the sps_ppa field is valid, since the DLPI
9820Sstevel@tonic-gate 	 * spec says that DL_PROMISCON_REQ can be issued at any state, i.e.,
9830Sstevel@tonic-gate 	 * the request can be issued even before DL_ATTACH_REQ or PPPIO_ATTACH
9840Sstevel@tonic-gate 	 * be issued to associate this stream with a ppa.
9850Sstevel@tonic-gate 	 */
9860Sstevel@tonic-gate 	if (ppa != NULL) {
9870Sstevel@tonic-gate 		rw_enter(&ppa->ppa_sib_lock, RW_WRITER);
9880Sstevel@tonic-gate 		ppa->ppa_promicnt++;
9890Sstevel@tonic-gate 		rw_exit(&ppa->ppa_sib_lock);
9900Sstevel@tonic-gate 	}
9910Sstevel@tonic-gate 	DBGDLPI((CE_CONT, "/%d: promiscuous mode on\n", sps->sps_mn_id));
9920Sstevel@tonic-gate 	dlokack(q, mp, DL_PROMISCON_REQ);
9930Sstevel@tonic-gate }
9940Sstevel@tonic-gate 
9950Sstevel@tonic-gate /*
9960Sstevel@tonic-gate  * sppp_dlpromiscoffreq()
9970Sstevel@tonic-gate  *
9980Sstevel@tonic-gate  * MT-Perimeters:
9990Sstevel@tonic-gate  *    shared inner, shared outer.
10000Sstevel@tonic-gate  *
10010Sstevel@tonic-gate  * Description:
10020Sstevel@tonic-gate  *    Perform DL_PROMISCOFF_REQ request, called by sppp_mproto.
10030Sstevel@tonic-gate  */
10040Sstevel@tonic-gate static int
sppp_dlpromiscoffreq(queue_t * q,mblk_t * mp,spppstr_t * sps)10050Sstevel@tonic-gate sppp_dlpromiscoffreq(queue_t *q, mblk_t *mp, spppstr_t *sps)
10060Sstevel@tonic-gate {
10070Sstevel@tonic-gate 	t_uscalar_t	level;
10080Sstevel@tonic-gate 
10090Sstevel@tonic-gate 	ASSERT(q != NULL && q->q_ptr != NULL);
10100Sstevel@tonic-gate 	ASSERT(mp != NULL && mp->b_rptr != NULL);
10110Sstevel@tonic-gate 	level = ((dl_promiscoff_req_t *)mp->b_rptr)->dl_level;
10120Sstevel@tonic-gate 	ASSERT(sps != NULL);
10130Sstevel@tonic-gate 
10140Sstevel@tonic-gate 	if (!IS_SPS_PROMISC(sps)) {
10150Sstevel@tonic-gate 		DBGERROR((CE_CONT, "DLPI promiscoff: not promiscuous\n"));
10160Sstevel@tonic-gate 		dlerrorack(q, mp, DL_PROMISCOFF_REQ, DL_NOTENAB, 0);
10170Sstevel@tonic-gate 	} else if ((level != DL_PROMISC_PHYS) && (level != DL_PROMISC_SAP) &&
10180Sstevel@tonic-gate 	    (level != DL_PROMISC_MULTI)) {
10190Sstevel@tonic-gate 		dlerrorack(q, mp, DL_PROMISCOFF_REQ, DL_NOTSUPPORTED, 0);
10200Sstevel@tonic-gate 		DBGERROR((CE_CONT, "DLPI promiscoff: bad level %d\n", level));
10210Sstevel@tonic-gate 	} else {
10220Sstevel@tonic-gate 		qwriter(q, mp, sppp_dl_promiscoff, PERIM_INNER);
10230Sstevel@tonic-gate 	}
10240Sstevel@tonic-gate 	return (0);
10250Sstevel@tonic-gate 
10260Sstevel@tonic-gate }
10270Sstevel@tonic-gate 
10280Sstevel@tonic-gate /*
10290Sstevel@tonic-gate  * sppp_dl_promiscoff()
10300Sstevel@tonic-gate  *
10310Sstevel@tonic-gate  * MT-Perimeters:
10320Sstevel@tonic-gate  *    exclusive inner, shared outer.
10330Sstevel@tonic-gate  *
10340Sstevel@tonic-gate  * Description:
10350Sstevel@tonic-gate  *    Called by qwriter (INNER) from sppp_dlpromiscoffreq as the result of
10360Sstevel@tonic-gate  *    receiving a DL_PROMISCOFF_REQ message.
10370Sstevel@tonic-gate  */
10380Sstevel@tonic-gate static void
sppp_dl_promiscoff(queue_t * q,mblk_t * mp)10390Sstevel@tonic-gate sppp_dl_promiscoff(queue_t *q, mblk_t *mp)
10400Sstevel@tonic-gate {
10410Sstevel@tonic-gate 	spppstr_t	*sps;
10420Sstevel@tonic-gate 	sppa_t		*ppa;
10430Sstevel@tonic-gate 
10440Sstevel@tonic-gate 	ASSERT(q != NULL && q->q_ptr != NULL);
10450Sstevel@tonic-gate 	sps = (spppstr_t *)q->q_ptr;
10460Sstevel@tonic-gate 	ASSERT(IS_SPS_PROMISC(sps));
10470Sstevel@tonic-gate 	ASSERT(mp != NULL && mp->b_rptr != NULL);
10480Sstevel@tonic-gate 	ppa = sps->sps_ppa;
10490Sstevel@tonic-gate 
10500Sstevel@tonic-gate 	sps->sps_flags &= ~SPS_PROMISC;
10510Sstevel@tonic-gate 	/*
10520Sstevel@tonic-gate 	 * We can't be guaranteed that the sps_ppa field is still valid, since
10530Sstevel@tonic-gate 	 * the control stream might have been closed earlier, in which case
10540Sstevel@tonic-gate 	 * the close procedure would have NULL'd out the sps_ppa.
10550Sstevel@tonic-gate 	 */
10560Sstevel@tonic-gate 	if (ppa != NULL) {
10570Sstevel@tonic-gate 		rw_enter(&ppa->ppa_sib_lock, RW_WRITER);
10580Sstevel@tonic-gate 		ASSERT(ppa->ppa_promicnt > 0);
10590Sstevel@tonic-gate 		ppa->ppa_promicnt--;
10600Sstevel@tonic-gate 		rw_exit(&ppa->ppa_sib_lock);
10610Sstevel@tonic-gate 	}
10620Sstevel@tonic-gate 	DBGDLPI((CE_CONT, "/%d: promiscuous mode off\n", sps->sps_mn_id));
10630Sstevel@tonic-gate 	dlokack(q, mp, DL_PROMISCOFF_REQ);
10640Sstevel@tonic-gate }
10650Sstevel@tonic-gate 
10660Sstevel@tonic-gate /*
10670Sstevel@tonic-gate  * sppp_dlphyreq()
10680Sstevel@tonic-gate  *
10690Sstevel@tonic-gate  * MT-Perimeters:
10700Sstevel@tonic-gate  *    shared inner, shared outer.
10710Sstevel@tonic-gate  *
10720Sstevel@tonic-gate  * Description:
10730Sstevel@tonic-gate  *    Perform DL_PHYS_ADDR_REQ request, called by sppp_mproto. This doesn't
10740Sstevel@tonic-gate  *    return anything useful, but it keeps ifconfig happy.
10750Sstevel@tonic-gate  */
10760Sstevel@tonic-gate /* ARGSUSED */
10770Sstevel@tonic-gate static int
sppp_dlphyreq(queue_t * q,mblk_t * mp,spppstr_t * us)10780Sstevel@tonic-gate sppp_dlphyreq(queue_t *q, mblk_t *mp, spppstr_t *us)
10790Sstevel@tonic-gate {
10800Sstevel@tonic-gate 	static struct ether_addr addr = { 0 };
10810Sstevel@tonic-gate 
10820Sstevel@tonic-gate 	dlphysaddrack(q, mp, (char *)&addr, ETHERADDRL);
10830Sstevel@tonic-gate 	return (0);
10840Sstevel@tonic-gate }
10850Sstevel@tonic-gate 
10860Sstevel@tonic-gate /*
10870Sstevel@tonic-gate  * sppp_dladdether()
10880Sstevel@tonic-gate  *
10890Sstevel@tonic-gate  * Description:
10900Sstevel@tonic-gate  *    Prepend an empty Ethernet header to msg for snoop, et al. Free
10910Sstevel@tonic-gate  *    the original mblk if alloc fails. Only called for the purpose of sending
10920Sstevel@tonic-gate  *    packets up the promiscous stream.
10930Sstevel@tonic-gate  */
10940Sstevel@tonic-gate /* ARGSUSED */
10950Sstevel@tonic-gate static mblk_t *
sppp_dladdether(spppstr_t * sps,mblk_t * mp,t_scalar_t proto)10960Sstevel@tonic-gate sppp_dladdether(spppstr_t *sps, mblk_t *mp, t_scalar_t proto)
10970Sstevel@tonic-gate {
10980Sstevel@tonic-gate 	mblk_t		*eh;
10990Sstevel@tonic-gate 	t_scalar_t	type;
11000Sstevel@tonic-gate 
11010Sstevel@tonic-gate 	if ((eh = allocb(sizeof (struct ether_header), BPRI_MED)) == NULL) {
11020Sstevel@tonic-gate 		freemsg(mp);
11030Sstevel@tonic-gate 		return (NULL);
11040Sstevel@tonic-gate 	}
11050Sstevel@tonic-gate 	if (proto == PPP_IP) {
11060Sstevel@tonic-gate 		type = ETHERTYPE_IP;
11070Sstevel@tonic-gate 	} else if (proto == PPP_IPV6) {
11080Sstevel@tonic-gate 		type = ETHERTYPE_IPV6;
11090Sstevel@tonic-gate 	} else {
11100Sstevel@tonic-gate 		/*
11110Sstevel@tonic-gate 		 * For all other protocols, end this up as an ETHERTYPE_PPP
11120Sstevel@tonic-gate 		 * type of packet. Since we've skipped the PPP headers in the
11130Sstevel@tonic-gate 		 * caller, make sure that we restore it. We know for sure that
11140Sstevel@tonic-gate 		 * the PPP header still exists in the message (only skipped),
11150Sstevel@tonic-gate 		 * since the sender of this message is pppd and it must have
11160Sstevel@tonic-gate 		 * included the PPP header in front.
11170Sstevel@tonic-gate 		 */
11180Sstevel@tonic-gate 		type = ETHERTYPE_PPP;
11190Sstevel@tonic-gate 		mp->b_rptr -= PPP_HDRLEN;
11200Sstevel@tonic-gate 		ASSERT(mp->b_rptr >= mp->b_datap->db_base);
11210Sstevel@tonic-gate 	}
11220Sstevel@tonic-gate 	eh->b_wptr += sizeof (struct ether_header);
11230Sstevel@tonic-gate 	bzero((caddr_t)eh->b_rptr, sizeof (struct ether_header));
11240Sstevel@tonic-gate 	((struct ether_header *)eh->b_rptr)->ether_type = htons((int16_t)type);
11250Sstevel@tonic-gate 
11260Sstevel@tonic-gate 	linkb(eh, mp);
11270Sstevel@tonic-gate 	return (eh);
11280Sstevel@tonic-gate }
11290Sstevel@tonic-gate 
11300Sstevel@tonic-gate /*
11310Sstevel@tonic-gate  * sppp_dladdud()
11320Sstevel@tonic-gate  *
11330Sstevel@tonic-gate  * Description:
11340Sstevel@tonic-gate  *    Prepend DL_UNITDATA_IND mblk to msg, free original alloc fails.
11350Sstevel@tonic-gate  */
11360Sstevel@tonic-gate /* ARGSUSED */
11370Sstevel@tonic-gate mblk_t *
sppp_dladdud(spppstr_t * sps,mblk_t * mp,t_scalar_t proto,boolean_t promisc)11380Sstevel@tonic-gate sppp_dladdud(spppstr_t *sps, mblk_t *mp, t_scalar_t proto, boolean_t promisc)
11390Sstevel@tonic-gate {
11400Sstevel@tonic-gate 	dl_unitdata_ind_t *dlu;
11410Sstevel@tonic-gate 	mblk_t		*dh;
11420Sstevel@tonic-gate 	size_t		size;
11430Sstevel@tonic-gate 	t_scalar_t	type;
11440Sstevel@tonic-gate 
11450Sstevel@tonic-gate 	size = sizeof (dl_unitdata_ind_t) + (2 * SPPP_ADDRL);
11460Sstevel@tonic-gate 	if ((dh = allocb(size, BPRI_MED)) == NULL) {
11470Sstevel@tonic-gate 		freemsg(mp);
11480Sstevel@tonic-gate 		return (NULL);
11490Sstevel@tonic-gate 	}
11500Sstevel@tonic-gate 
11510Sstevel@tonic-gate 	dh->b_datap->db_type = M_PROTO;
11520Sstevel@tonic-gate 	dh->b_wptr = dh->b_datap->db_lim;
11530Sstevel@tonic-gate 	dh->b_rptr = dh->b_wptr - size;
11540Sstevel@tonic-gate 
11550Sstevel@tonic-gate 	dlu = (dl_unitdata_ind_t *)dh->b_rptr;
11560Sstevel@tonic-gate 	dlu->dl_primitive = DL_UNITDATA_IND;
11570Sstevel@tonic-gate 	dlu->dl_dest_addr_length = SPPP_ADDRL;
11580Sstevel@tonic-gate 	dlu->dl_dest_addr_offset = sizeof (dl_unitdata_ind_t);
11590Sstevel@tonic-gate 	dlu->dl_src_addr_length = SPPP_ADDRL;
11600Sstevel@tonic-gate 	dlu->dl_src_addr_offset = sizeof (dl_unitdata_ind_t) + SPPP_ADDRL;
11610Sstevel@tonic-gate 	dlu->dl_group_address = 0;
11620Sstevel@tonic-gate 
11630Sstevel@tonic-gate 	if (promisc) {
11640Sstevel@tonic-gate 		if (proto == PPP_IP) {
11650Sstevel@tonic-gate 			type = ETHERTYPE_IP;
11660Sstevel@tonic-gate 		} else if (proto == PPP_IPV6) {
11670Sstevel@tonic-gate 			type = ETHERTYPE_IPV6;
11680Sstevel@tonic-gate 		} else {
11690Sstevel@tonic-gate 			/*
11700Sstevel@tonic-gate 			 * For all other protocols, send this up as an
11710Sstevel@tonic-gate 			 * ETHERTYPE_PPP type of packet. Since we've skipped
11720Sstevel@tonic-gate 			 * the PPP headers in the caller, make sure that we
11730Sstevel@tonic-gate 			 * restore it. We know for sure that the PPP header
11740Sstevel@tonic-gate 			 * still exists in the message (only skipped), since
11750Sstevel@tonic-gate 			 * the sender of this message is pppd and it must
11760Sstevel@tonic-gate 			 * have included the PPP header in front.
11770Sstevel@tonic-gate 			 */
11780Sstevel@tonic-gate 			type = ETHERTYPE_PPP;
11790Sstevel@tonic-gate 			mp->b_rptr -= PPP_HDRLEN;
11800Sstevel@tonic-gate 			ASSERT(mp->b_rptr >= mp->b_datap->db_base);
11810Sstevel@tonic-gate 		}
11820Sstevel@tonic-gate 	} else {
11830Sstevel@tonic-gate 		type = sps->sps_req_sap;
11840Sstevel@tonic-gate 	}
11850Sstevel@tonic-gate 	/*
11860Sstevel@tonic-gate 	 * Send the DLPI client the data with the SAP they requested,
11870Sstevel@tonic-gate 	 * (e.g. ETHERTYPE_IP) rather than the PPP protocol (e.g. PPP_IP).
11880Sstevel@tonic-gate 	 */
11890Sstevel@tonic-gate 	((spppreqsap_t *)(dlu + 1))[0] = type;
11900Sstevel@tonic-gate 	((spppreqsap_t *)(dlu + 1))[1] = type;
11910Sstevel@tonic-gate 
11920Sstevel@tonic-gate 	linkb(dh, mp);
11930Sstevel@tonic-gate 	return (dh);
11940Sstevel@tonic-gate }
11950Sstevel@tonic-gate 
11960Sstevel@tonic-gate /*
11970Sstevel@tonic-gate  * sppp_dlprsendup()
11980Sstevel@tonic-gate  *
11990Sstevel@tonic-gate  * Description:
12000Sstevel@tonic-gate  *    For any valid promiscuous streams (marked with SPS_PROMISC and its
12010Sstevel@tonic-gate  *    sps_dlstate is DL_IDLE), send data upstream. The caller is expected
12020Sstevel@tonic-gate  *    to hold ppa_sib_lock when calling this procedure.
12030Sstevel@tonic-gate  */
12040Sstevel@tonic-gate void
sppp_dlprsendup(spppstr_t * sps,mblk_t * mp,t_scalar_t proto,boolean_t header)12050Sstevel@tonic-gate sppp_dlprsendup(spppstr_t *sps, mblk_t *mp, t_scalar_t proto, boolean_t header)
12060Sstevel@tonic-gate {
12070Sstevel@tonic-gate 	sppa_t	*ppa;
12080Sstevel@tonic-gate 	mblk_t	*dmp;
12090Sstevel@tonic-gate 
12100Sstevel@tonic-gate 	ASSERT(sps != NULL);
12110Sstevel@tonic-gate 	ASSERT(mp != NULL && mp->b_rptr != NULL);
12120Sstevel@tonic-gate 	ppa = sps->sps_ppa;
12130Sstevel@tonic-gate 	ASSERT(ppa != NULL);
12140Sstevel@tonic-gate 
12150Sstevel@tonic-gate 	/* NOTE: caller must hold ppa_sib_lock in RW_READER mode */
12160Sstevel@tonic-gate 	ASSERT(RW_READ_HELD(&ppa->ppa_sib_lock));
12170Sstevel@tonic-gate 
12180Sstevel@tonic-gate 	for (; sps != NULL; sps = sps->sps_nextsib) {
12190Sstevel@tonic-gate 		/*
12200Sstevel@tonic-gate 		 * We specifically test to ensure that the DLPI state for the
12210Sstevel@tonic-gate 		 * promiscous stream is IDLE (DL_IDLE), since such state tells
12220Sstevel@tonic-gate 		 * us that the promiscous stream has been bound to PPP_ALLSAP.
12230Sstevel@tonic-gate 		 */
12240Sstevel@tonic-gate 		if (IS_SPS_PROMISC(sps) && (sps->sps_dlstate == DL_IDLE) &&
12250Sstevel@tonic-gate 		    canputnext(sps->sps_rq)) {
12260Sstevel@tonic-gate 			if ((dmp = dupmsg(mp)) == NULL) {
12270Sstevel@tonic-gate 				mutex_enter(&ppa->ppa_sta_lock);
12280Sstevel@tonic-gate 				ppa->ppa_allocbfail++;
12290Sstevel@tonic-gate 				mutex_exit(&ppa->ppa_sta_lock);
12300Sstevel@tonic-gate 				continue;
12310Sstevel@tonic-gate 			}
12320Sstevel@tonic-gate 			if (header) {
12330Sstevel@tonic-gate 				dmp->b_rptr += PPP_HDRLEN;
12340Sstevel@tonic-gate 			}
12350Sstevel@tonic-gate 			if (IS_SPS_RAWDATA(sps)) {
12360Sstevel@tonic-gate 				/* function frees original message if fails */
12370Sstevel@tonic-gate 				dmp = sppp_dladdether(sps, dmp, proto);
12380Sstevel@tonic-gate 			} else {
12390Sstevel@tonic-gate 				/* function frees original message if fails */
12400Sstevel@tonic-gate 				dmp = sppp_dladdud(sps, dmp, proto, B_TRUE);
12410Sstevel@tonic-gate 			}
12420Sstevel@tonic-gate 			if (dmp != NULL) {
12430Sstevel@tonic-gate 				putnext(sps->sps_rq, dmp);
12440Sstevel@tonic-gate 			} else {
12450Sstevel@tonic-gate 				mutex_enter(&ppa->ppa_sta_lock);
12460Sstevel@tonic-gate 				ppa->ppa_allocbfail++;
12470Sstevel@tonic-gate 				mutex_exit(&ppa->ppa_sta_lock);
12480Sstevel@tonic-gate 			}
12490Sstevel@tonic-gate 		}
12500Sstevel@tonic-gate 	}
12510Sstevel@tonic-gate }
1252