xref: /illumos-gate/usr/src/uts/common/io/ppp/sppp/sppp_dlpi.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * sppp_dlpi.c - Solaris STREAMS PPP multiplexing pseudo-driver DLPI handlers
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
5*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
6*7c478bd9Sstevel@tonic-gate  *
7*7c478bd9Sstevel@tonic-gate  * Permission to use, copy, modify, and distribute this software and its
8*7c478bd9Sstevel@tonic-gate  * documentation is hereby granted, provided that the above copyright
9*7c478bd9Sstevel@tonic-gate  * notice appears in all copies.
10*7c478bd9Sstevel@tonic-gate  *
11*7c478bd9Sstevel@tonic-gate  * SUN MAKES NO REPRESENTATION OR WARRANTIES ABOUT THE SUITABILITY OF
12*7c478bd9Sstevel@tonic-gate  * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
13*7c478bd9Sstevel@tonic-gate  * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
14*7c478bd9Sstevel@tonic-gate  * PARTICULAR PURPOSE, OR NON-INFRINGEMENT.  SUN SHALL NOT BE LIABLE FOR
15*7c478bd9Sstevel@tonic-gate  * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
16*7c478bd9Sstevel@tonic-gate  * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES
17*7c478bd9Sstevel@tonic-gate  *
18*7c478bd9Sstevel@tonic-gate  * Copyright (c) 1994 The Australian National University.
19*7c478bd9Sstevel@tonic-gate  * All rights reserved.
20*7c478bd9Sstevel@tonic-gate  *
21*7c478bd9Sstevel@tonic-gate  * Permission to use, copy, modify, and distribute this software and its
22*7c478bd9Sstevel@tonic-gate  * documentation is hereby granted, provided that the above copyright
23*7c478bd9Sstevel@tonic-gate  * notice appears in all copies.  This software is provided without any
24*7c478bd9Sstevel@tonic-gate  * warranty, express or implied. The Australian National University
25*7c478bd9Sstevel@tonic-gate  * makes no representations about the suitability of this software for
26*7c478bd9Sstevel@tonic-gate  * any purpose.
27*7c478bd9Sstevel@tonic-gate  *
28*7c478bd9Sstevel@tonic-gate  * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
29*7c478bd9Sstevel@tonic-gate  * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
30*7c478bd9Sstevel@tonic-gate  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
31*7c478bd9Sstevel@tonic-gate  * THE AUSTRALIAN NATIONAL UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY
32*7c478bd9Sstevel@tonic-gate  * OF SUCH DAMAGE.
33*7c478bd9Sstevel@tonic-gate  *
34*7c478bd9Sstevel@tonic-gate  * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
35*7c478bd9Sstevel@tonic-gate  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
36*7c478bd9Sstevel@tonic-gate  * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
37*7c478bd9Sstevel@tonic-gate  * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
38*7c478bd9Sstevel@tonic-gate  * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
39*7c478bd9Sstevel@tonic-gate  * OR MODIFICATIONS.
40*7c478bd9Sstevel@tonic-gate  *
41*7c478bd9Sstevel@tonic-gate  * This driver is derived from the original SVR4 STREAMS PPP driver
42*7c478bd9Sstevel@tonic-gate  * originally written by Paul Mackerras <paul.mackerras@cs.anu.edu.au>.
43*7c478bd9Sstevel@tonic-gate  *
44*7c478bd9Sstevel@tonic-gate  * Adi Masputra <adi.masputra@sun.com> rewrote and restructured the code
45*7c478bd9Sstevel@tonic-gate  * for improved performance and scalability.
46*7c478bd9Sstevel@tonic-gate  */
47*7c478bd9Sstevel@tonic-gate 
48*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
49*7c478bd9Sstevel@tonic-gate #define	RCSID	"$Id: sppp_dlpi.c,v 1.0 2000/05/08 01:10:12 masputra Exp $"
50*7c478bd9Sstevel@tonic-gate 
51*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
52*7c478bd9Sstevel@tonic-gate #include <sys/param.h>
53*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
54*7c478bd9Sstevel@tonic-gate #include <sys/stream.h>
55*7c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
56*7c478bd9Sstevel@tonic-gate #include <sys/errno.h>
57*7c478bd9Sstevel@tonic-gate #include <sys/time.h>
58*7c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
59*7c478bd9Sstevel@tonic-gate #include <sys/conf.h>
60*7c478bd9Sstevel@tonic-gate #include <sys/dlpi.h>
61*7c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
62*7c478bd9Sstevel@tonic-gate #include <sys/kstat.h>
63*7c478bd9Sstevel@tonic-gate #include <sys/strsun.h>
64*7c478bd9Sstevel@tonic-gate #include <sys/ethernet.h>
65*7c478bd9Sstevel@tonic-gate #include <net/ppp_defs.h>
66*7c478bd9Sstevel@tonic-gate #include <netinet/in.h>
67*7c478bd9Sstevel@tonic-gate #include <net/pppio.h>
68*7c478bd9Sstevel@tonic-gate #include "s_common.h"
69*7c478bd9Sstevel@tonic-gate #include "sppp.h"
70*7c478bd9Sstevel@tonic-gate 
71*7c478bd9Sstevel@tonic-gate static int	sppp_dlattachreq(queue_t *, mblk_t *, spppstr_t *);
72*7c478bd9Sstevel@tonic-gate static int	sppp_dldetachreq(queue_t *, mblk_t *, spppstr_t *);
73*7c478bd9Sstevel@tonic-gate static int	sppp_dlbindreq(queue_t *, mblk_t *, spppstr_t *);
74*7c478bd9Sstevel@tonic-gate static int	sppp_dlunbindreq(queue_t *, mblk_t *, spppstr_t *);
75*7c478bd9Sstevel@tonic-gate static int	sppp_dlinforeq(queue_t *, mblk_t *, spppstr_t *);
76*7c478bd9Sstevel@tonic-gate static int	sppp_dlunitdatareq(queue_t *, mblk_t *, spppstr_t *);
77*7c478bd9Sstevel@tonic-gate static int	sppp_dlpromisconreq(queue_t *, mblk_t *, spppstr_t *);
78*7c478bd9Sstevel@tonic-gate static int	sppp_dlpromiscoffreq(queue_t *, mblk_t *, spppstr_t *);
79*7c478bd9Sstevel@tonic-gate static int	sppp_dlphyreq(queue_t *, mblk_t *, spppstr_t *);
80*7c478bd9Sstevel@tonic-gate static void	sppp_dl_attach_upper(queue_t *, mblk_t *);
81*7c478bd9Sstevel@tonic-gate static void	sppp_dl_detach_upper(queue_t *, mblk_t *);
82*7c478bd9Sstevel@tonic-gate static void	sppp_dl_bind(queue_t *, mblk_t *);
83*7c478bd9Sstevel@tonic-gate static void	sppp_dl_unbind(queue_t *, mblk_t *);
84*7c478bd9Sstevel@tonic-gate static void	sppp_dl_promiscon(queue_t *, mblk_t *);
85*7c478bd9Sstevel@tonic-gate static void	sppp_dl_promiscoff(queue_t *, mblk_t *);
86*7c478bd9Sstevel@tonic-gate static mblk_t	*sppp_dladdether(spppstr_t *, mblk_t *, t_scalar_t);
87*7c478bd9Sstevel@tonic-gate 
88*7c478bd9Sstevel@tonic-gate static struct sppp_dlpi_pinfo_t dl_pinfo[DL_MAXPRIM + 1];
89*7c478bd9Sstevel@tonic-gate 
90*7c478bd9Sstevel@tonic-gate #if 0
91*7c478bd9Sstevel@tonic-gate #define	DBGERROR(x)	cmn_err x
92*7c478bd9Sstevel@tonic-gate #else
93*7c478bd9Sstevel@tonic-gate #define	DBGERROR(x)	((void)0)
94*7c478bd9Sstevel@tonic-gate #endif
95*7c478bd9Sstevel@tonic-gate 
96*7c478bd9Sstevel@tonic-gate /* #define	DBG_DLPI	1 */
97*7c478bd9Sstevel@tonic-gate 
98*7c478bd9Sstevel@tonic-gate #ifdef DBG_DLPI
99*7c478bd9Sstevel@tonic-gate struct sppp_dlpi_entry {
100*7c478bd9Sstevel@tonic-gate 	uint32_t sde_val;
101*7c478bd9Sstevel@tonic-gate 	const char *sde_name;
102*7c478bd9Sstevel@tonic-gate };
103*7c478bd9Sstevel@tonic-gate 
104*7c478bd9Sstevel@tonic-gate static const struct sppp_dlpi_entry sppp_dlpi_list[] = {
105*7c478bd9Sstevel@tonic-gate 	{ DL_INFO_REQ, "DL_INFO_REQ" },
106*7c478bd9Sstevel@tonic-gate 	{ DL_INFO_ACK, "DL_INFO_ACK" },
107*7c478bd9Sstevel@tonic-gate 	{ DL_ATTACH_REQ, "DL_ATTACH_REQ" },
108*7c478bd9Sstevel@tonic-gate 	{ DL_DETACH_REQ, "DL_DETACH_REQ" },
109*7c478bd9Sstevel@tonic-gate 	{ DL_BIND_REQ, "DL_BIND_REQ" },
110*7c478bd9Sstevel@tonic-gate 	{ DL_BIND_ACK, "DL_BIND_ACK" },
111*7c478bd9Sstevel@tonic-gate 	{ DL_UNBIND_REQ, "DL_UNBIND_REQ" },
112*7c478bd9Sstevel@tonic-gate 	{ DL_OK_ACK, "DL_OK_ACK" },
113*7c478bd9Sstevel@tonic-gate 	{ DL_ERROR_ACK, "DL_ERROR_ACK" },
114*7c478bd9Sstevel@tonic-gate 	{ DL_SUBS_BIND_REQ, "DL_SUBS_BIND_REQ" },
115*7c478bd9Sstevel@tonic-gate 	{ DL_SUBS_BIND_ACK, "DL_SUBS_BIND_ACK" },
116*7c478bd9Sstevel@tonic-gate 	{ DL_SUBS_UNBIND_REQ, "DL_SUBS_UNBIND_REQ" },
117*7c478bd9Sstevel@tonic-gate 	{ DL_ENABMULTI_REQ, "DL_ENABMULTI_REQ" },
118*7c478bd9Sstevel@tonic-gate 	{ DL_DISABMULTI_REQ, "DL_DISABMULTI_REQ" },
119*7c478bd9Sstevel@tonic-gate 	{ DL_PROMISCON_REQ, "DL_PROMISCON_REQ" },
120*7c478bd9Sstevel@tonic-gate 	{ DL_PROMISCOFF_REQ, "DL_PROMISCOFF_REQ" },
121*7c478bd9Sstevel@tonic-gate 	{ DL_UNITDATA_REQ, "DL_UNITDATA_REQ" },
122*7c478bd9Sstevel@tonic-gate 	{ DL_UNITDATA_IND, "DL_UNITDATA_IND" },
123*7c478bd9Sstevel@tonic-gate 	{ DL_UDERROR_IND, "DL_UDERROR_IND" },
124*7c478bd9Sstevel@tonic-gate 	{ DL_UDQOS_REQ, "DL_UDQOS_REQ" },
125*7c478bd9Sstevel@tonic-gate 	{ DL_CONNECT_REQ, "DL_CONNECT_REQ" },
126*7c478bd9Sstevel@tonic-gate 	{ DL_CONNECT_IND, "DL_CONNECT_IND" },
127*7c478bd9Sstevel@tonic-gate 	{ DL_CONNECT_RES, "DL_CONNECT_RES" },
128*7c478bd9Sstevel@tonic-gate 	{ DL_CONNECT_CON, "DL_CONNECT_CON" },
129*7c478bd9Sstevel@tonic-gate 	{ DL_TOKEN_REQ, "DL_TOKEN_REQ" },
130*7c478bd9Sstevel@tonic-gate 	{ DL_TOKEN_ACK, "DL_TOKEN_ACK" },
131*7c478bd9Sstevel@tonic-gate 	{ DL_DISCONNECT_REQ, "DL_DISCONNECT_REQ" },
132*7c478bd9Sstevel@tonic-gate 	{ DL_DISCONNECT_IND, "DL_DISCONNECT_IND" },
133*7c478bd9Sstevel@tonic-gate 	{ DL_RESET_REQ, "DL_RESET_REQ" },
134*7c478bd9Sstevel@tonic-gate 	{ DL_RESET_IND, "DL_RESET_IND" },
135*7c478bd9Sstevel@tonic-gate 	{ DL_RESET_RES, "DL_RESET_RES" },
136*7c478bd9Sstevel@tonic-gate 	{ DL_RESET_CON, "DL_RESET_CON" },
137*7c478bd9Sstevel@tonic-gate 	{ DL_DATA_ACK_REQ, "DL_DATA_ACK_REQ" },
138*7c478bd9Sstevel@tonic-gate 	{ DL_DATA_ACK_IND, "DL_DATA_ACK_IND" },
139*7c478bd9Sstevel@tonic-gate 	{ DL_DATA_ACK_STATUS_IND, "DL_DATA_ACK_STATUS_IND" },
140*7c478bd9Sstevel@tonic-gate 	{ DL_REPLY_REQ, "DL_REPLY_REQ" },
141*7c478bd9Sstevel@tonic-gate 	{ DL_REPLY_IND, "DL_REPLY_IND" },
142*7c478bd9Sstevel@tonic-gate 	{ DL_REPLY_STATUS_IND, "DL_REPLY_STATUS_IND" },
143*7c478bd9Sstevel@tonic-gate 	{ DL_REPLY_UPDATE_REQ, "DL_REPLY_UPDATE_REQ" },
144*7c478bd9Sstevel@tonic-gate 	{ DL_REPLY_UPDATE_STATUS_IND, "DL_REPLY_UPDATE_STATUS_IND" },
145*7c478bd9Sstevel@tonic-gate 	{ DL_XID_REQ, "DL_XID_REQ" },
146*7c478bd9Sstevel@tonic-gate 	{ DL_XID_IND, "DL_XID_IND" },
147*7c478bd9Sstevel@tonic-gate 	{ DL_XID_RES, "DL_XID_RES" },
148*7c478bd9Sstevel@tonic-gate 	{ DL_XID_CON, "DL_XID_CON" },
149*7c478bd9Sstevel@tonic-gate 	{ DL_TEST_REQ, "DL_TEST_REQ" },
150*7c478bd9Sstevel@tonic-gate 	{ DL_TEST_IND, "DL_TEST_IND" },
151*7c478bd9Sstevel@tonic-gate 	{ DL_TEST_RES, "DL_TEST_RES" },
152*7c478bd9Sstevel@tonic-gate 	{ DL_TEST_CON, "DL_TEST_CON" },
153*7c478bd9Sstevel@tonic-gate 	{ DL_PHYS_ADDR_REQ, "DL_PHYS_ADDR_REQ" },
154*7c478bd9Sstevel@tonic-gate 	{ DL_PHYS_ADDR_ACK, "DL_PHYS_ADDR_ACK" },
155*7c478bd9Sstevel@tonic-gate 	{ DL_SET_PHYS_ADDR_REQ, "DL_SET_PHYS_ADDR_REQ" },
156*7c478bd9Sstevel@tonic-gate 	{ DL_GET_STATISTICS_REQ, "DL_GET_STATISTICS_REQ" },
157*7c478bd9Sstevel@tonic-gate 	{ DL_GET_STATISTICS_ACK, "DL_GET_STATISTICS_ACK" },
158*7c478bd9Sstevel@tonic-gate 	{ 0, NULL }
159*7c478bd9Sstevel@tonic-gate };
160*7c478bd9Sstevel@tonic-gate 
161*7c478bd9Sstevel@tonic-gate static const struct sppp_dlpi_entry sppp_state_list[] = {
162*7c478bd9Sstevel@tonic-gate 	{ DL_UNBOUND, "DL_UNBOUND" },
163*7c478bd9Sstevel@tonic-gate 	{ DL_BIND_PENDING, "DL_BIND_PENDING" },
164*7c478bd9Sstevel@tonic-gate 	{ DL_UNBIND_PENDING, "DL_UNBIND_PENDING" },
165*7c478bd9Sstevel@tonic-gate 	{ DL_IDLE, "DL_IDLE" },
166*7c478bd9Sstevel@tonic-gate 	{ DL_UNATTACHED, "DL_UNATTACHED" },
167*7c478bd9Sstevel@tonic-gate 	{ DL_ATTACH_PENDING, "DL_ATTACH_PENDING" },
168*7c478bd9Sstevel@tonic-gate 	{ DL_DETACH_PENDING, "DL_DETACH_PENDING" },
169*7c478bd9Sstevel@tonic-gate 	{ DL_UDQOS_PENDING, "DL_UDQOS_PENDING" },
170*7c478bd9Sstevel@tonic-gate 	{ DL_OUTCON_PENDING, "DL_OUTCON_PENDING" },
171*7c478bd9Sstevel@tonic-gate 	{ DL_INCON_PENDING, "DL_INCON_PENDING" },
172*7c478bd9Sstevel@tonic-gate 	{ DL_CONN_RES_PENDING, "DL_CONN_RES_PENDING" },
173*7c478bd9Sstevel@tonic-gate 	{ DL_DATAXFER, "DL_DATAXFER" },
174*7c478bd9Sstevel@tonic-gate 	{ DL_USER_RESET_PENDING, "DL_USER_RESET_PENDING" },
175*7c478bd9Sstevel@tonic-gate 	{ DL_PROV_RESET_PENDING, "DL_PROV_RESET_PENDING" },
176*7c478bd9Sstevel@tonic-gate 	{ DL_RESET_RES_PENDING, "DL_RESET_RES_PENDING" },
177*7c478bd9Sstevel@tonic-gate 	{ DL_DISCON8_PENDING, "DL_DISCON8_PENDING" },
178*7c478bd9Sstevel@tonic-gate 	{ DL_DISCON9_PENDING, "DL_DISCON9_PENDING" },
179*7c478bd9Sstevel@tonic-gate 	{ DL_DISCON11_PENDING, "DL_DISCON11_PENDING" },
180*7c478bd9Sstevel@tonic-gate 	{ DL_DISCON12_PENDING, "DL_DISCON12_PENDING" },
181*7c478bd9Sstevel@tonic-gate 	{ DL_DISCON13_PENDING, "DL_DISCON13_PENDING" },
182*7c478bd9Sstevel@tonic-gate 	{ DL_SUBS_BIND_PND, "DL_SUBS_BIND_PND" },
183*7c478bd9Sstevel@tonic-gate 	{ DL_SUBS_UNBIND_PND, "DL_SUBS_UNBIND_PND" },
184*7c478bd9Sstevel@tonic-gate 	{ 0, NULL }
185*7c478bd9Sstevel@tonic-gate };
186*7c478bd9Sstevel@tonic-gate 
187*7c478bd9Sstevel@tonic-gate static const char *
188*7c478bd9Sstevel@tonic-gate prim2name(uint32_t prim)
189*7c478bd9Sstevel@tonic-gate {
190*7c478bd9Sstevel@tonic-gate 	const struct sppp_dlpi_entry *sde;
191*7c478bd9Sstevel@tonic-gate 
192*7c478bd9Sstevel@tonic-gate 	for (sde = sppp_dlpi_list; sde->sde_name != NULL; sde++)
193*7c478bd9Sstevel@tonic-gate 		if (sde->sde_val == prim)
194*7c478bd9Sstevel@tonic-gate 			break;
195*7c478bd9Sstevel@tonic-gate 	return (sde->sde_name);
196*7c478bd9Sstevel@tonic-gate }
197*7c478bd9Sstevel@tonic-gate 
198*7c478bd9Sstevel@tonic-gate static const char *
199*7c478bd9Sstevel@tonic-gate state2name(uint32_t state)
200*7c478bd9Sstevel@tonic-gate {
201*7c478bd9Sstevel@tonic-gate 	const struct sppp_dlpi_entry *sde;
202*7c478bd9Sstevel@tonic-gate 
203*7c478bd9Sstevel@tonic-gate 	for (sde = sppp_state_list; sde->sde_name != NULL; sde++)
204*7c478bd9Sstevel@tonic-gate 		if (sde->sde_val == state)
205*7c478bd9Sstevel@tonic-gate 			break;
206*7c478bd9Sstevel@tonic-gate 	return (sde->sde_name);
207*7c478bd9Sstevel@tonic-gate }
208*7c478bd9Sstevel@tonic-gate 
209*7c478bd9Sstevel@tonic-gate #define	DBGDLPI(x)	cmn_err x
210*7c478bd9Sstevel@tonic-gate #else
211*7c478bd9Sstevel@tonic-gate #define	DBGDLPI(x)	((void)0)
212*7c478bd9Sstevel@tonic-gate #endif /* DBG_DLPI */
213*7c478bd9Sstevel@tonic-gate 
214*7c478bd9Sstevel@tonic-gate /*
215*7c478bd9Sstevel@tonic-gate  * DL_INFO_ACK template for point-to-point interface.
216*7c478bd9Sstevel@tonic-gate  */
217*7c478bd9Sstevel@tonic-gate static dl_info_ack_t	sppp_infoack = {
218*7c478bd9Sstevel@tonic-gate 	DL_INFO_ACK,			/* dl_primitive */
219*7c478bd9Sstevel@tonic-gate 	PPP_MAXMTU,			/* dl_max_sdu */
220*7c478bd9Sstevel@tonic-gate 	0,				/* dl_min_sdu */
221*7c478bd9Sstevel@tonic-gate 	SPPP_ADDRL,			/* dl_addr_length */
222*7c478bd9Sstevel@tonic-gate 	/*
223*7c478bd9Sstevel@tonic-gate 	 * snoop et. al. don't know about DL_OTHER so this entry
224*7c478bd9Sstevel@tonic-gate 	 * was changed to DL_ETHER so ethernet tracing/snooping
225*7c478bd9Sstevel@tonic-gate 	 * facilities will work with PPP interfaces.
226*7c478bd9Sstevel@tonic-gate 	 */
227*7c478bd9Sstevel@tonic-gate 	DL_ETHER,			/* dl_mac_type */
228*7c478bd9Sstevel@tonic-gate 	0,				/* dl_reserved */
229*7c478bd9Sstevel@tonic-gate 	0,				/* dl_current_state */
230*7c478bd9Sstevel@tonic-gate 	SPPP_SAPL,			/* dl_sap_length */
231*7c478bd9Sstevel@tonic-gate 	DL_CLDLS,			/* dl_service_mode */
232*7c478bd9Sstevel@tonic-gate 	0,				/* dl_qos_length */
233*7c478bd9Sstevel@tonic-gate 	0,				/* dl_qos_offset */
234*7c478bd9Sstevel@tonic-gate 	0,				/* dl_range_length */
235*7c478bd9Sstevel@tonic-gate 	0,				/* dl_range_offset */
236*7c478bd9Sstevel@tonic-gate 	DL_STYLE2,			/* dl_provider_style */
237*7c478bd9Sstevel@tonic-gate 	sizeof (dl_info_ack_t),		/* dl_addr_offset */
238*7c478bd9Sstevel@tonic-gate 	DL_VERSION_2,			/* dl_version */
239*7c478bd9Sstevel@tonic-gate 	0,				/* dl_brdcst_addr_length */
240*7c478bd9Sstevel@tonic-gate 	0,				/* dl_brdcst_addr_offset */
241*7c478bd9Sstevel@tonic-gate 	0				/* dl_growth */
242*7c478bd9Sstevel@tonic-gate };
243*7c478bd9Sstevel@tonic-gate 
244*7c478bd9Sstevel@tonic-gate /*
245*7c478bd9Sstevel@tonic-gate  * sppp_dlpi_pinfoinit()
246*7c478bd9Sstevel@tonic-gate  *
247*7c478bd9Sstevel@tonic-gate  * Description:
248*7c478bd9Sstevel@tonic-gate  *    Initialize dl_pinfo[], called from sppp_attach.
249*7c478bd9Sstevel@tonic-gate  */
250*7c478bd9Sstevel@tonic-gate void
251*7c478bd9Sstevel@tonic-gate sppp_dlpi_pinfoinit(void)
252*7c478bd9Sstevel@tonic-gate {
253*7c478bd9Sstevel@tonic-gate 	bzero(dl_pinfo, sizeof (dl_pinfo));	/* Just to be safe */
254*7c478bd9Sstevel@tonic-gate 
255*7c478bd9Sstevel@tonic-gate 	dl_pinfo[DL_ATTACH_REQ].pi_minlen = sizeof (dl_attach_req_t);
256*7c478bd9Sstevel@tonic-gate 	dl_pinfo[DL_ATTACH_REQ].pi_state = DL_UNATTACHED;
257*7c478bd9Sstevel@tonic-gate 	dl_pinfo[DL_ATTACH_REQ].pi_funcp = sppp_dlattachreq;
258*7c478bd9Sstevel@tonic-gate 
259*7c478bd9Sstevel@tonic-gate 	dl_pinfo[DL_DETACH_REQ].pi_minlen = sizeof (dl_detach_req_t);
260*7c478bd9Sstevel@tonic-gate 	dl_pinfo[DL_DETACH_REQ].pi_state = DL_UNBOUND;
261*7c478bd9Sstevel@tonic-gate 	dl_pinfo[DL_DETACH_REQ].pi_funcp = sppp_dldetachreq;
262*7c478bd9Sstevel@tonic-gate 
263*7c478bd9Sstevel@tonic-gate 	dl_pinfo[DL_BIND_REQ].pi_minlen = sizeof (dl_bind_req_t);
264*7c478bd9Sstevel@tonic-gate 	dl_pinfo[DL_BIND_REQ].pi_state = DL_UNBOUND;
265*7c478bd9Sstevel@tonic-gate 	dl_pinfo[DL_BIND_REQ].pi_funcp = sppp_dlbindreq;
266*7c478bd9Sstevel@tonic-gate 
267*7c478bd9Sstevel@tonic-gate 	dl_pinfo[DL_UNBIND_REQ].pi_minlen = sizeof (dl_unbind_req_t);
268*7c478bd9Sstevel@tonic-gate 	dl_pinfo[DL_UNBIND_REQ].pi_state = DL_IDLE;
269*7c478bd9Sstevel@tonic-gate 	dl_pinfo[DL_UNBIND_REQ].pi_funcp = sppp_dlunbindreq;
270*7c478bd9Sstevel@tonic-gate 
271*7c478bd9Sstevel@tonic-gate 	dl_pinfo[DL_INFO_REQ].pi_minlen = sizeof (dl_info_req_t);
272*7c478bd9Sstevel@tonic-gate 	dl_pinfo[DL_INFO_REQ].pi_state = 0;	/* special handling */
273*7c478bd9Sstevel@tonic-gate 	dl_pinfo[DL_INFO_REQ].pi_funcp = sppp_dlinforeq;
274*7c478bd9Sstevel@tonic-gate 
275*7c478bd9Sstevel@tonic-gate 	dl_pinfo[DL_UNITDATA_REQ].pi_minlen = sizeof (dl_unitdata_req_t);
276*7c478bd9Sstevel@tonic-gate 	dl_pinfo[DL_UNITDATA_REQ].pi_state = DL_IDLE;
277*7c478bd9Sstevel@tonic-gate 	dl_pinfo[DL_UNITDATA_REQ].pi_funcp = sppp_dlunitdatareq;
278*7c478bd9Sstevel@tonic-gate 
279*7c478bd9Sstevel@tonic-gate 	dl_pinfo[DL_PROMISCON_REQ].pi_minlen = sizeof (dl_promiscon_req_t);
280*7c478bd9Sstevel@tonic-gate 	dl_pinfo[DL_PROMISCON_REQ].pi_state = 0; /* special handling */
281*7c478bd9Sstevel@tonic-gate 	dl_pinfo[DL_PROMISCON_REQ].pi_funcp = sppp_dlpromisconreq;
282*7c478bd9Sstevel@tonic-gate 
283*7c478bd9Sstevel@tonic-gate 	dl_pinfo[DL_PROMISCOFF_REQ].pi_minlen = sizeof (dl_promiscoff_req_t);
284*7c478bd9Sstevel@tonic-gate 	dl_pinfo[DL_PROMISCOFF_REQ].pi_state = 0; /* special handling */
285*7c478bd9Sstevel@tonic-gate 	dl_pinfo[DL_PROMISCOFF_REQ].pi_funcp = sppp_dlpromiscoffreq;
286*7c478bd9Sstevel@tonic-gate 
287*7c478bd9Sstevel@tonic-gate 	dl_pinfo[DL_PHYS_ADDR_REQ].pi_minlen = sizeof (dl_phys_addr_req_t);
288*7c478bd9Sstevel@tonic-gate 	dl_pinfo[DL_PHYS_ADDR_REQ].pi_state = 0; /* special handling */
289*7c478bd9Sstevel@tonic-gate 	dl_pinfo[DL_PHYS_ADDR_REQ].pi_funcp = sppp_dlphyreq;
290*7c478bd9Sstevel@tonic-gate }
291*7c478bd9Sstevel@tonic-gate 
292*7c478bd9Sstevel@tonic-gate /*
293*7c478bd9Sstevel@tonic-gate  * sppp_mproto()
294*7c478bd9Sstevel@tonic-gate  *
295*7c478bd9Sstevel@tonic-gate  * MT-Perimeters:
296*7c478bd9Sstevel@tonic-gate  *    shared inner, shared outer.
297*7c478bd9Sstevel@tonic-gate  *
298*7c478bd9Sstevel@tonic-gate  * Description:
299*7c478bd9Sstevel@tonic-gate  *    Handle M_PCPROTO/M_PROTO messages, called by sppp_uwput.
300*7c478bd9Sstevel@tonic-gate  */
301*7c478bd9Sstevel@tonic-gate int
302*7c478bd9Sstevel@tonic-gate sppp_mproto(queue_t *q, mblk_t *mp, spppstr_t *sps)
303*7c478bd9Sstevel@tonic-gate {
304*7c478bd9Sstevel@tonic-gate 	union DL_primitives *dlp;
305*7c478bd9Sstevel@tonic-gate 	struct sppp_dlpi_pinfo_t *dpi;
306*7c478bd9Sstevel@tonic-gate 	t_uscalar_t	prim;
307*7c478bd9Sstevel@tonic-gate 	int		len;
308*7c478bd9Sstevel@tonic-gate 	int		error = 0;
309*7c478bd9Sstevel@tonic-gate 
310*7c478bd9Sstevel@tonic-gate 	ASSERT(!IS_SPS_CONTROL(sps));
311*7c478bd9Sstevel@tonic-gate 	if ((len = MBLKL(mp)) < sizeof (t_uscalar_t)) {
312*7c478bd9Sstevel@tonic-gate 		DBGERROR((CE_CONT, "bad mproto: block length %d\n", len));
313*7c478bd9Sstevel@tonic-gate 		merror(q, mp, EPROTO);
314*7c478bd9Sstevel@tonic-gate 		return (0);
315*7c478bd9Sstevel@tonic-gate 	}
316*7c478bd9Sstevel@tonic-gate 	dlp = (union DL_primitives *)mp->b_rptr;
317*7c478bd9Sstevel@tonic-gate 	prim = dlp->dl_primitive;
318*7c478bd9Sstevel@tonic-gate 	if (prim > DL_MAXPRIM) {
319*7c478bd9Sstevel@tonic-gate 		DBGERROR((CE_CONT, "bad mproto: primitive %d > %d\n", prim,
320*7c478bd9Sstevel@tonic-gate 		    DL_MAXPRIM));
321*7c478bd9Sstevel@tonic-gate 		error = DL_BADPRIM;
322*7c478bd9Sstevel@tonic-gate 	} else {
323*7c478bd9Sstevel@tonic-gate 		dpi = &dl_pinfo[prim];
324*7c478bd9Sstevel@tonic-gate 		if (dpi->pi_funcp == NULL) {
325*7c478bd9Sstevel@tonic-gate 			DBGERROR((CE_CONT,
326*7c478bd9Sstevel@tonic-gate 			    "bad mproto: primitive %d not supported\n", prim));
327*7c478bd9Sstevel@tonic-gate 			error = DL_NOTSUPPORTED;
328*7c478bd9Sstevel@tonic-gate 		} else if (len < dpi->pi_minlen) {
329*7c478bd9Sstevel@tonic-gate 			DBGERROR((CE_CONT,
330*7c478bd9Sstevel@tonic-gate 			    "bad mproto: primitive len %d < %d\n", len,
331*7c478bd9Sstevel@tonic-gate 			    dpi->pi_minlen));
332*7c478bd9Sstevel@tonic-gate 			error = DL_BADPRIM;
333*7c478bd9Sstevel@tonic-gate 		} else if ((dpi->pi_state != 0) &&
334*7c478bd9Sstevel@tonic-gate 		    (sps->sps_dlstate != dpi->pi_state)) {
335*7c478bd9Sstevel@tonic-gate 			DBGERROR((CE_CONT,
336*7c478bd9Sstevel@tonic-gate 			    "bad state %d != %d for primitive %d\n",
337*7c478bd9Sstevel@tonic-gate 			    sps->sps_dlstate, dpi->pi_state, prim));
338*7c478bd9Sstevel@tonic-gate 			error = DL_OUTSTATE;
339*7c478bd9Sstevel@tonic-gate 		}
340*7c478bd9Sstevel@tonic-gate 	}
341*7c478bd9Sstevel@tonic-gate 	if (error != 0) {
342*7c478bd9Sstevel@tonic-gate 		dlerrorack(q, mp, dlp->dl_primitive, error, 0);
343*7c478bd9Sstevel@tonic-gate 		return (0);
344*7c478bd9Sstevel@tonic-gate 	}
345*7c478bd9Sstevel@tonic-gate #ifdef DBG_DLPI
346*7c478bd9Sstevel@tonic-gate 	{
347*7c478bd9Sstevel@tonic-gate 		const char *cp = prim2name(prim);
348*7c478bd9Sstevel@tonic-gate 		if (cp != NULL)
349*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "/%d: Dispatching %s\n",
350*7c478bd9Sstevel@tonic-gate 			    sps->sps_mn_id, cp);
351*7c478bd9Sstevel@tonic-gate 		else
352*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT,
353*7c478bd9Sstevel@tonic-gate 			    "/%d: Dispatching unknown primitive %d\n",
354*7c478bd9Sstevel@tonic-gate 			    sps->sps_mn_id, prim);
355*7c478bd9Sstevel@tonic-gate 	}
356*7c478bd9Sstevel@tonic-gate #endif
357*7c478bd9Sstevel@tonic-gate 	return ((*dpi->pi_funcp)(q, mp, sps));
358*7c478bd9Sstevel@tonic-gate }
359*7c478bd9Sstevel@tonic-gate 
360*7c478bd9Sstevel@tonic-gate /*
361*7c478bd9Sstevel@tonic-gate  * sppp_dlattachreq()
362*7c478bd9Sstevel@tonic-gate  *
363*7c478bd9Sstevel@tonic-gate  * MT-Perimeters:
364*7c478bd9Sstevel@tonic-gate  *    shared inner, shared outer.
365*7c478bd9Sstevel@tonic-gate  *
366*7c478bd9Sstevel@tonic-gate  * Description:
367*7c478bd9Sstevel@tonic-gate  *    Perform DL_ATTACH_REQ request, called by sppp_mproto.
368*7c478bd9Sstevel@tonic-gate  */
369*7c478bd9Sstevel@tonic-gate static int
370*7c478bd9Sstevel@tonic-gate sppp_dlattachreq(queue_t *q, mblk_t *mp, spppstr_t *sps)
371*7c478bd9Sstevel@tonic-gate {
372*7c478bd9Sstevel@tonic-gate 	int	error = 0;
373*7c478bd9Sstevel@tonic-gate 	union DL_primitives *dlp;
374*7c478bd9Sstevel@tonic-gate 
375*7c478bd9Sstevel@tonic-gate 	ASSERT(q != NULL && q->q_ptr != NULL);
376*7c478bd9Sstevel@tonic-gate 	ASSERT(mp != NULL && mp->b_rptr != NULL);
377*7c478bd9Sstevel@tonic-gate 	dlp = (union DL_primitives *)mp->b_rptr;
378*7c478bd9Sstevel@tonic-gate 	ASSERT(sps != NULL);
379*7c478bd9Sstevel@tonic-gate 	ASSERT(sps->sps_dlstate == DL_UNATTACHED);
380*7c478bd9Sstevel@tonic-gate 
381*7c478bd9Sstevel@tonic-gate 	if (IS_SPS_PIOATTACH(sps)) {
382*7c478bd9Sstevel@tonic-gate 		DBGERROR((CE_CONT, "DLPI attach: already attached\n"));
383*7c478bd9Sstevel@tonic-gate 		error = EINVAL;
384*7c478bd9Sstevel@tonic-gate 	}
385*7c478bd9Sstevel@tonic-gate 	if (error != 0) {
386*7c478bd9Sstevel@tonic-gate 		dlerrorack(q, mp, dlp->dl_primitive, DL_OUTSTATE, error);
387*7c478bd9Sstevel@tonic-gate 	} else {
388*7c478bd9Sstevel@tonic-gate 		qwriter(q, mp, sppp_dl_attach_upper, PERIM_OUTER);
389*7c478bd9Sstevel@tonic-gate 	}
390*7c478bd9Sstevel@tonic-gate 	return (0);
391*7c478bd9Sstevel@tonic-gate }
392*7c478bd9Sstevel@tonic-gate 
393*7c478bd9Sstevel@tonic-gate /*
394*7c478bd9Sstevel@tonic-gate  * sppp_dl_attach_upper()
395*7c478bd9Sstevel@tonic-gate  *
396*7c478bd9Sstevel@tonic-gate  * MT-Perimeters:
397*7c478bd9Sstevel@tonic-gate  *    exclusive inner, exclusive outer.
398*7c478bd9Sstevel@tonic-gate  *
399*7c478bd9Sstevel@tonic-gate  * Description:
400*7c478bd9Sstevel@tonic-gate  *    Called by qwriter (INNER) from sppp_dlattachreq as the result of
401*7c478bd9Sstevel@tonic-gate  *    receiving a DL_ATTACH_REQ message.
402*7c478bd9Sstevel@tonic-gate  */
403*7c478bd9Sstevel@tonic-gate static void
404*7c478bd9Sstevel@tonic-gate sppp_dl_attach_upper(queue_t *q, mblk_t *mp)
405*7c478bd9Sstevel@tonic-gate {
406*7c478bd9Sstevel@tonic-gate 	sppa_t		*ppa;
407*7c478bd9Sstevel@tonic-gate 	spppstr_t	*sps;
408*7c478bd9Sstevel@tonic-gate 	union DL_primitives *dlp;
409*7c478bd9Sstevel@tonic-gate 
410*7c478bd9Sstevel@tonic-gate 	ASSERT(q != NULL && q->q_ptr != NULL);
411*7c478bd9Sstevel@tonic-gate 	sps = (spppstr_t *)q->q_ptr;
412*7c478bd9Sstevel@tonic-gate 	ASSERT(!IS_SPS_PIOATTACH(sps));
413*7c478bd9Sstevel@tonic-gate 	ASSERT(mp != NULL && mp->b_rptr != NULL);
414*7c478bd9Sstevel@tonic-gate 	dlp = (union DL_primitives *)mp->b_rptr;
415*7c478bd9Sstevel@tonic-gate 
416*7c478bd9Sstevel@tonic-gate 	/* If there's something here, it's detached. */
417*7c478bd9Sstevel@tonic-gate 	if (sps->sps_ppa != NULL) {
418*7c478bd9Sstevel@tonic-gate 		sppp_remove_ppa(sps);
419*7c478bd9Sstevel@tonic-gate 	}
420*7c478bd9Sstevel@tonic-gate 
421*7c478bd9Sstevel@tonic-gate 	ppa = sppp_find_ppa(dlp->attach_req.dl_ppa);
422*7c478bd9Sstevel@tonic-gate 	if (ppa == NULL)
423*7c478bd9Sstevel@tonic-gate 		ppa = sppp_create_ppa(dlp->attach_req.dl_ppa);
424*7c478bd9Sstevel@tonic-gate 
425*7c478bd9Sstevel@tonic-gate 	/*
426*7c478bd9Sstevel@tonic-gate 	 * If we can't find it, then it's either because the requestor
427*7c478bd9Sstevel@tonic-gate 	 * has supplied a wrong dl_ppa to be attached to, or because
428*7c478bd9Sstevel@tonic-gate 	 * the control stream for the specified ppa has been closed
429*7c478bd9Sstevel@tonic-gate 	 * before we get here.
430*7c478bd9Sstevel@tonic-gate 	 */
431*7c478bd9Sstevel@tonic-gate 	if (ppa == NULL) {
432*7c478bd9Sstevel@tonic-gate 		DBGERROR((CE_CONT, "DLPI attach: cannot create ppa %u\n",
433*7c478bd9Sstevel@tonic-gate 		    dlp->attach_req.dl_ppa));
434*7c478bd9Sstevel@tonic-gate 		dlerrorack(q, mp, dlp->dl_primitive, DL_SYSERR, ENOMEM);
435*7c478bd9Sstevel@tonic-gate 		return;
436*7c478bd9Sstevel@tonic-gate 	}
437*7c478bd9Sstevel@tonic-gate 	/*
438*7c478bd9Sstevel@tonic-gate 	 * Preallocate the hangup message so that we're always able to
439*7c478bd9Sstevel@tonic-gate 	 * send this upstream in the event of a catastrophic failure.
440*7c478bd9Sstevel@tonic-gate 	 */
441*7c478bd9Sstevel@tonic-gate 	if ((sps->sps_hangup = allocb(1, BPRI_MED)) == NULL) {
442*7c478bd9Sstevel@tonic-gate 		DBGERROR((CE_CONT, "DLPI attach: cannot allocate hangup\n"));
443*7c478bd9Sstevel@tonic-gate 		dlerrorack(q, mp, dlp->dl_primitive, DL_SYSERR, ENOSR);
444*7c478bd9Sstevel@tonic-gate 		return;
445*7c478bd9Sstevel@tonic-gate 	}
446*7c478bd9Sstevel@tonic-gate 	sps->sps_dlstate = DL_UNBOUND;
447*7c478bd9Sstevel@tonic-gate 	sps->sps_ppa = ppa;
448*7c478bd9Sstevel@tonic-gate 	/*
449*7c478bd9Sstevel@tonic-gate 	 * Add this stream to the head of the list of sibling streams
450*7c478bd9Sstevel@tonic-gate 	 * which belong to the specified ppa.
451*7c478bd9Sstevel@tonic-gate 	 */
452*7c478bd9Sstevel@tonic-gate 	rw_enter(&ppa->ppa_sib_lock, RW_WRITER);
453*7c478bd9Sstevel@tonic-gate 	ppa->ppa_refcnt++;
454*7c478bd9Sstevel@tonic-gate 	sps->sps_nextsib = ppa->ppa_streams;
455*7c478bd9Sstevel@tonic-gate 	ppa->ppa_streams = sps;
456*7c478bd9Sstevel@tonic-gate 	/*
457*7c478bd9Sstevel@tonic-gate 	 * And if this stream was marked as promiscuous (SPS_PROMISC), then we
458*7c478bd9Sstevel@tonic-gate 	 * need to update the promiscuous streams count. This should only
459*7c478bd9Sstevel@tonic-gate 	 * happen when DL_PROMISCON_REQ was issued prior to attachment.
460*7c478bd9Sstevel@tonic-gate 	 */
461*7c478bd9Sstevel@tonic-gate 	if (IS_SPS_PROMISC(sps)) {
462*7c478bd9Sstevel@tonic-gate 		ppa->ppa_promicnt++;
463*7c478bd9Sstevel@tonic-gate 	}
464*7c478bd9Sstevel@tonic-gate 	rw_exit(&ppa->ppa_sib_lock);
465*7c478bd9Sstevel@tonic-gate 	DBGDLPI((CE_CONT, "/%d: attached to ppa %d\n", sps->sps_mn_id,
466*7c478bd9Sstevel@tonic-gate 	    ppa->ppa_ppa_id));
467*7c478bd9Sstevel@tonic-gate 	dlokack(q, mp, DL_ATTACH_REQ);
468*7c478bd9Sstevel@tonic-gate }
469*7c478bd9Sstevel@tonic-gate 
470*7c478bd9Sstevel@tonic-gate /*
471*7c478bd9Sstevel@tonic-gate  * sppp_dldetachreq()
472*7c478bd9Sstevel@tonic-gate  *
473*7c478bd9Sstevel@tonic-gate  * MT-Perimeters:
474*7c478bd9Sstevel@tonic-gate  *    shared inner, shared outer.
475*7c478bd9Sstevel@tonic-gate  *
476*7c478bd9Sstevel@tonic-gate  * Description:
477*7c478bd9Sstevel@tonic-gate  *    Perform DL_DETACH_REQ request, called by sppp_mproto.
478*7c478bd9Sstevel@tonic-gate  */
479*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
480*7c478bd9Sstevel@tonic-gate static int
481*7c478bd9Sstevel@tonic-gate sppp_dldetachreq(queue_t *q, mblk_t *mp, spppstr_t *sps)
482*7c478bd9Sstevel@tonic-gate {
483*7c478bd9Sstevel@tonic-gate 	ASSERT(q != NULL && q->q_ptr != NULL);
484*7c478bd9Sstevel@tonic-gate 	ASSERT(mp != NULL && mp->b_rptr != NULL);
485*7c478bd9Sstevel@tonic-gate 	ASSERT(sps != NULL);
486*7c478bd9Sstevel@tonic-gate 	ASSERT(sps->sps_dlstate == DL_UNBOUND);
487*7c478bd9Sstevel@tonic-gate 	ASSERT(!IS_SPS_PIOATTACH(sps));
488*7c478bd9Sstevel@tonic-gate 
489*7c478bd9Sstevel@tonic-gate 	qwriter(q, mp, sppp_dl_detach_upper, PERIM_INNER);
490*7c478bd9Sstevel@tonic-gate 	return (0);
491*7c478bd9Sstevel@tonic-gate }
492*7c478bd9Sstevel@tonic-gate 
493*7c478bd9Sstevel@tonic-gate /*
494*7c478bd9Sstevel@tonic-gate  * sppp_dl_detach_upper()
495*7c478bd9Sstevel@tonic-gate  *
496*7c478bd9Sstevel@tonic-gate  * MT-Perimeters:
497*7c478bd9Sstevel@tonic-gate  *    exclusive inner, shared outer.
498*7c478bd9Sstevel@tonic-gate  *
499*7c478bd9Sstevel@tonic-gate  * Description:
500*7c478bd9Sstevel@tonic-gate  *    Called by qwriter (INNER) from sppp_dldetachreq as the result of
501*7c478bd9Sstevel@tonic-gate  *    receiving a DL_DETACH_REQ message.
502*7c478bd9Sstevel@tonic-gate  */
503*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
504*7c478bd9Sstevel@tonic-gate static void
505*7c478bd9Sstevel@tonic-gate sppp_dl_detach_upper(queue_t *q, mblk_t *mp)
506*7c478bd9Sstevel@tonic-gate {
507*7c478bd9Sstevel@tonic-gate 	spppstr_t	*sps;
508*7c478bd9Sstevel@tonic-gate 
509*7c478bd9Sstevel@tonic-gate 	ASSERT(q != NULL && q->q_ptr != NULL);
510*7c478bd9Sstevel@tonic-gate 	ASSERT(mp != NULL && mp->b_rptr != NULL);
511*7c478bd9Sstevel@tonic-gate 	sps = (spppstr_t *)q->q_ptr;
512*7c478bd9Sstevel@tonic-gate 	/*
513*7c478bd9Sstevel@tonic-gate 	 * We don't actually detach from the PPA until closed or
514*7c478bd9Sstevel@tonic-gate 	 * reattached.
515*7c478bd9Sstevel@tonic-gate 	 */
516*7c478bd9Sstevel@tonic-gate 	sps->sps_flags &= ~SPS_PROMISC;	/* clear flag anyway */
517*7c478bd9Sstevel@tonic-gate 	sps->sps_dlstate = DL_UNATTACHED;
518*7c478bd9Sstevel@tonic-gate 	dlokack(q, mp, DL_DETACH_REQ);
519*7c478bd9Sstevel@tonic-gate }
520*7c478bd9Sstevel@tonic-gate 
521*7c478bd9Sstevel@tonic-gate /*
522*7c478bd9Sstevel@tonic-gate  * sppp_dlbindreq()
523*7c478bd9Sstevel@tonic-gate  *
524*7c478bd9Sstevel@tonic-gate  * MT-Perimeters:
525*7c478bd9Sstevel@tonic-gate  *    shared inner, shared outer.
526*7c478bd9Sstevel@tonic-gate  *
527*7c478bd9Sstevel@tonic-gate  * Description:
528*7c478bd9Sstevel@tonic-gate  *    Perform DL_BIND_REQ request, called by sppp_mproto.
529*7c478bd9Sstevel@tonic-gate  */
530*7c478bd9Sstevel@tonic-gate static int
531*7c478bd9Sstevel@tonic-gate sppp_dlbindreq(queue_t *q, mblk_t *mp, spppstr_t *sps)
532*7c478bd9Sstevel@tonic-gate {
533*7c478bd9Sstevel@tonic-gate 	sppa_t			*ppa;
534*7c478bd9Sstevel@tonic-gate 	union DL_primitives	*dlp;
535*7c478bd9Sstevel@tonic-gate 	spppreqsap_t		req_sap;
536*7c478bd9Sstevel@tonic-gate 	int			error = 0;
537*7c478bd9Sstevel@tonic-gate 
538*7c478bd9Sstevel@tonic-gate 	ASSERT(q != NULL && q->q_ptr != NULL);
539*7c478bd9Sstevel@tonic-gate 	ASSERT(mp != NULL && mp->b_rptr != NULL);
540*7c478bd9Sstevel@tonic-gate 	dlp = (union DL_primitives *)mp->b_rptr;
541*7c478bd9Sstevel@tonic-gate 	req_sap = dlp->bind_req.dl_sap;
542*7c478bd9Sstevel@tonic-gate 	ASSERT(sps != NULL);
543*7c478bd9Sstevel@tonic-gate 	ASSERT(!IS_SPS_PIOATTACH(sps));
544*7c478bd9Sstevel@tonic-gate 	ASSERT(sps->sps_dlstate == DL_UNBOUND);
545*7c478bd9Sstevel@tonic-gate 
546*7c478bd9Sstevel@tonic-gate 	ppa = sps->sps_ppa;
547*7c478bd9Sstevel@tonic-gate 	if (ppa == NULL) {
548*7c478bd9Sstevel@tonic-gate 		DBGERROR((CE_CONT, "DLPI bind: no attached ppa\n"));
549*7c478bd9Sstevel@tonic-gate 		error = DL_OUTSTATE;
550*7c478bd9Sstevel@tonic-gate 	} else if ((req_sap != ETHERTYPE_IP) && (req_sap != ETHERTYPE_IPV6) &&
551*7c478bd9Sstevel@tonic-gate 		(req_sap != ETHERTYPE_ALLSAP)) {
552*7c478bd9Sstevel@tonic-gate 		DBGERROR((CE_CONT, "DLPI bind: unknown SAP %x\n", req_sap));
553*7c478bd9Sstevel@tonic-gate 		error = DL_BADADDR;
554*7c478bd9Sstevel@tonic-gate 	}
555*7c478bd9Sstevel@tonic-gate 	if (error != 0) {
556*7c478bd9Sstevel@tonic-gate 		dlerrorack(q, mp, dlp->dl_primitive, error, 0);
557*7c478bd9Sstevel@tonic-gate 	} else {
558*7c478bd9Sstevel@tonic-gate 		qwriter(q, mp, sppp_dl_bind, PERIM_INNER);
559*7c478bd9Sstevel@tonic-gate 	}
560*7c478bd9Sstevel@tonic-gate 	return (0);
561*7c478bd9Sstevel@tonic-gate }
562*7c478bd9Sstevel@tonic-gate 
563*7c478bd9Sstevel@tonic-gate /*
564*7c478bd9Sstevel@tonic-gate  * sppp_dl_bind()
565*7c478bd9Sstevel@tonic-gate  *
566*7c478bd9Sstevel@tonic-gate  * MT-Perimeters:
567*7c478bd9Sstevel@tonic-gate  *    exclusive inner, shared outer.
568*7c478bd9Sstevel@tonic-gate  *
569*7c478bd9Sstevel@tonic-gate  * Description:
570*7c478bd9Sstevel@tonic-gate  *    Called by qwriter (INNER) from sppp_dlbindreq as the result of
571*7c478bd9Sstevel@tonic-gate  *    receiving a DL_BIND_REQ message.
572*7c478bd9Sstevel@tonic-gate  */
573*7c478bd9Sstevel@tonic-gate static void
574*7c478bd9Sstevel@tonic-gate sppp_dl_bind(queue_t *q, mblk_t *mp)
575*7c478bd9Sstevel@tonic-gate {
576*7c478bd9Sstevel@tonic-gate 	spppstr_t		*sps;
577*7c478bd9Sstevel@tonic-gate 	sppa_t			*ppa;
578*7c478bd9Sstevel@tonic-gate 	union DL_primitives	*dlp;
579*7c478bd9Sstevel@tonic-gate 	t_scalar_t		sap;
580*7c478bd9Sstevel@tonic-gate 	spppreqsap_t		req_sap;
581*7c478bd9Sstevel@tonic-gate 	mblk_t			*lsmp;
582*7c478bd9Sstevel@tonic-gate 
583*7c478bd9Sstevel@tonic-gate 	ASSERT(q != NULL && q->q_ptr != NULL);
584*7c478bd9Sstevel@tonic-gate 	sps = (spppstr_t *)q->q_ptr;
585*7c478bd9Sstevel@tonic-gate 	ASSERT(mp != NULL && mp->b_rptr != NULL);
586*7c478bd9Sstevel@tonic-gate 	dlp = (union DL_primitives *)mp->b_rptr;
587*7c478bd9Sstevel@tonic-gate 	ppa = sps->sps_ppa;
588*7c478bd9Sstevel@tonic-gate 	ASSERT(ppa != NULL);
589*7c478bd9Sstevel@tonic-gate 	req_sap = dlp->bind_req.dl_sap;
590*7c478bd9Sstevel@tonic-gate 	ASSERT((req_sap == ETHERTYPE_IP) || (req_sap == ETHERTYPE_IPV6) ||
591*7c478bd9Sstevel@tonic-gate 		(req_sap == ETHERTYPE_ALLSAP));
592*7c478bd9Sstevel@tonic-gate 
593*7c478bd9Sstevel@tonic-gate 	if (req_sap == ETHERTYPE_IP) {
594*7c478bd9Sstevel@tonic-gate 		sap = PPP_IP;
595*7c478bd9Sstevel@tonic-gate 	} else if (req_sap == ETHERTYPE_IPV6) {
596*7c478bd9Sstevel@tonic-gate 		sap = PPP_IPV6;
597*7c478bd9Sstevel@tonic-gate 	} else if (req_sap == ETHERTYPE_ALLSAP) {
598*7c478bd9Sstevel@tonic-gate 		sap = PPP_ALLSAP;
599*7c478bd9Sstevel@tonic-gate 	}
600*7c478bd9Sstevel@tonic-gate 	/*
601*7c478bd9Sstevel@tonic-gate 	 * If there's another stream with the same sap has already been bound
602*7c478bd9Sstevel@tonic-gate 	 * to the same ppa, then return with DL_NOADDR. However, we do make an
603*7c478bd9Sstevel@tonic-gate 	 * exception for snoop (req_sap=0x00, sap=0xff) since multiple
604*7c478bd9Sstevel@tonic-gate 	 * instances of snoop may execute an a given device.
605*7c478bd9Sstevel@tonic-gate 	 */
606*7c478bd9Sstevel@tonic-gate 	lsmp = NULL;
607*7c478bd9Sstevel@tonic-gate 	if (sap != PPP_ALLSAP) {
608*7c478bd9Sstevel@tonic-gate 		if ((sap == PPP_IP) && (ppa->ppa_ip_cache == NULL)) {
609*7c478bd9Sstevel@tonic-gate 			ppa->ppa_ip_cache = sps;
610*7c478bd9Sstevel@tonic-gate 			if (ppa->ppa_ctl != NULL) {
611*7c478bd9Sstevel@tonic-gate 				lsmp = create_lsmsg(PPP_LINKSTAT_IPV4_BOUND);
612*7c478bd9Sstevel@tonic-gate 			}
613*7c478bd9Sstevel@tonic-gate 		} else if ((sap == PPP_IPV6) && (ppa->ppa_ip6_cache == NULL)) {
614*7c478bd9Sstevel@tonic-gate 			ppa->ppa_ip6_cache = sps;
615*7c478bd9Sstevel@tonic-gate 			if (ppa->ppa_ctl != NULL) {
616*7c478bd9Sstevel@tonic-gate 				lsmp = create_lsmsg(PPP_LINKSTAT_IPV6_BOUND);
617*7c478bd9Sstevel@tonic-gate 			}
618*7c478bd9Sstevel@tonic-gate 		} else {
619*7c478bd9Sstevel@tonic-gate 			DBGERROR((CE_CONT, "DLPI bind: bad SAP %x\n", sap));
620*7c478bd9Sstevel@tonic-gate 			dlerrorack(q, mp, dlp->dl_primitive, DL_NOADDR,
621*7c478bd9Sstevel@tonic-gate 			    EEXIST);
622*7c478bd9Sstevel@tonic-gate 			return;
623*7c478bd9Sstevel@tonic-gate 		}
624*7c478bd9Sstevel@tonic-gate 		sps->sps_flags |= SPS_CACHED;
625*7c478bd9Sstevel@tonic-gate 	}
626*7c478bd9Sstevel@tonic-gate 	/*
627*7c478bd9Sstevel@tonic-gate 	 * Tell the daemon that a DLPI bind has happened on this stream,
628*7c478bd9Sstevel@tonic-gate 	 * and we'll only do this for PPP_IP or PPP_IPV6 sap (not snoop).
629*7c478bd9Sstevel@tonic-gate 	 */
630*7c478bd9Sstevel@tonic-gate 	if (lsmp != NULL && ppa->ppa_ctl != NULL) {
631*7c478bd9Sstevel@tonic-gate #ifdef DBG_DLPI
632*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "sending up %s\n",
633*7c478bd9Sstevel@tonic-gate 		    ((sap == PPP_IP) ? "PPP_LINKSTAT_IPV4_BOUND" :
634*7c478bd9Sstevel@tonic-gate 		    "PPP_LINKSTAT_IPV6_BOUND"));
635*7c478bd9Sstevel@tonic-gate #endif
636*7c478bd9Sstevel@tonic-gate 		putnext(ppa->ppa_ctl->sps_rq, lsmp);
637*7c478bd9Sstevel@tonic-gate 	}
638*7c478bd9Sstevel@tonic-gate 	DBGDLPI((CE_CONT, "/%d: bound to sap %X (req %X)\n", sps->sps_mn_id,
639*7c478bd9Sstevel@tonic-gate 	    sap, req_sap));
640*7c478bd9Sstevel@tonic-gate 	sps->sps_req_sap = req_sap;
641*7c478bd9Sstevel@tonic-gate 	sps->sps_sap = sap;
642*7c478bd9Sstevel@tonic-gate 	sps->sps_dlstate = DL_IDLE;
643*7c478bd9Sstevel@tonic-gate 	dlbindack(q, mp, req_sap, &sap, sizeof (int32_t), 0, 0);
644*7c478bd9Sstevel@tonic-gate }
645*7c478bd9Sstevel@tonic-gate 
646*7c478bd9Sstevel@tonic-gate /*
647*7c478bd9Sstevel@tonic-gate  * sppp_dlunbindreq()
648*7c478bd9Sstevel@tonic-gate  *
649*7c478bd9Sstevel@tonic-gate  * MT-Perimeters:
650*7c478bd9Sstevel@tonic-gate  *    shared inner, shared outer.
651*7c478bd9Sstevel@tonic-gate  *
652*7c478bd9Sstevel@tonic-gate  * Description:
653*7c478bd9Sstevel@tonic-gate  *    Perform DL_UNBIND_REQ request, called by sppp_mproto.
654*7c478bd9Sstevel@tonic-gate  */
655*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
656*7c478bd9Sstevel@tonic-gate static int
657*7c478bd9Sstevel@tonic-gate sppp_dlunbindreq(queue_t *q, mblk_t *mp, spppstr_t *sps)
658*7c478bd9Sstevel@tonic-gate {
659*7c478bd9Sstevel@tonic-gate 	ASSERT(q != NULL && q->q_ptr != NULL);
660*7c478bd9Sstevel@tonic-gate 	ASSERT(mp != NULL && mp->b_rptr != NULL);
661*7c478bd9Sstevel@tonic-gate 	ASSERT(sps != NULL);
662*7c478bd9Sstevel@tonic-gate 	ASSERT(!IS_SPS_PIOATTACH(sps));
663*7c478bd9Sstevel@tonic-gate 	ASSERT(sps->sps_dlstate == DL_IDLE);
664*7c478bd9Sstevel@tonic-gate 
665*7c478bd9Sstevel@tonic-gate 	qwriter(q, mp, sppp_dl_unbind, PERIM_INNER);
666*7c478bd9Sstevel@tonic-gate 	return (0);
667*7c478bd9Sstevel@tonic-gate }
668*7c478bd9Sstevel@tonic-gate 
669*7c478bd9Sstevel@tonic-gate /*
670*7c478bd9Sstevel@tonic-gate  * sppp_dl_unbind()
671*7c478bd9Sstevel@tonic-gate  *
672*7c478bd9Sstevel@tonic-gate  * MT-Perimeters:
673*7c478bd9Sstevel@tonic-gate  *    exclusive inner, shared outer.
674*7c478bd9Sstevel@tonic-gate  *
675*7c478bd9Sstevel@tonic-gate  * Description:
676*7c478bd9Sstevel@tonic-gate  *    Called by qwriter (INNER) from sppp_dlunbindreq as the result of
677*7c478bd9Sstevel@tonic-gate  *    receiving a DL_UNBIND_REQ message.
678*7c478bd9Sstevel@tonic-gate  */
679*7c478bd9Sstevel@tonic-gate static void
680*7c478bd9Sstevel@tonic-gate sppp_dl_unbind(queue_t *q, mblk_t *mp)
681*7c478bd9Sstevel@tonic-gate {
682*7c478bd9Sstevel@tonic-gate 	spppstr_t	*sps;
683*7c478bd9Sstevel@tonic-gate 	sppa_t		*ppa;
684*7c478bd9Sstevel@tonic-gate 	t_scalar_t	sap;
685*7c478bd9Sstevel@tonic-gate 	mblk_t		*msg;
686*7c478bd9Sstevel@tonic-gate 	boolean_t	saydown;
687*7c478bd9Sstevel@tonic-gate 
688*7c478bd9Sstevel@tonic-gate 	ASSERT(q != NULL && q->q_ptr != NULL);
689*7c478bd9Sstevel@tonic-gate 	sps = (spppstr_t *)q->q_ptr;
690*7c478bd9Sstevel@tonic-gate 	ppa = sps->sps_ppa;
691*7c478bd9Sstevel@tonic-gate 	ASSERT(mp != NULL && mp->b_rptr != NULL);
692*7c478bd9Sstevel@tonic-gate 	sap = sps->sps_sap;
693*7c478bd9Sstevel@tonic-gate 	ASSERT((sap == PPP_IP) || (sap == PPP_IPV6) || (sap == PPP_ALLSAP));
694*7c478bd9Sstevel@tonic-gate 
695*7c478bd9Sstevel@tonic-gate 	/* Flush messages on unbind, per DLPI specification. */
696*7c478bd9Sstevel@tonic-gate 	flushq(WR(q), FLUSHALL);
697*7c478bd9Sstevel@tonic-gate 	flushq(RD(q), FLUSHALL);
698*7c478bd9Sstevel@tonic-gate 
699*7c478bd9Sstevel@tonic-gate 	if ((ppa != NULL) && IS_SPS_CACHED(sps)) {
700*7c478bd9Sstevel@tonic-gate 		sps->sps_flags &= ~SPS_CACHED;
701*7c478bd9Sstevel@tonic-gate 		msg = NULL;
702*7c478bd9Sstevel@tonic-gate 		saydown = (ppa->ppa_ctl != NULL &&
703*7c478bd9Sstevel@tonic-gate 		    (sps->sps_npmode == NPMODE_PASS ||
704*7c478bd9Sstevel@tonic-gate 			sps->sps_npmode == NPMODE_QUEUE));
705*7c478bd9Sstevel@tonic-gate 		if (sap == PPP_IP) {
706*7c478bd9Sstevel@tonic-gate 			ppa->ppa_ip_cache = NULL;
707*7c478bd9Sstevel@tonic-gate 			if (saydown)
708*7c478bd9Sstevel@tonic-gate 				msg = create_lsmsg(PPP_LINKSTAT_IPV4_UNBOUND);
709*7c478bd9Sstevel@tonic-gate 		} else if (sap == PPP_IPV6) {
710*7c478bd9Sstevel@tonic-gate 			ppa->ppa_ip6_cache = NULL;
711*7c478bd9Sstevel@tonic-gate 			if (saydown)
712*7c478bd9Sstevel@tonic-gate 				msg = create_lsmsg(PPP_LINKSTAT_IPV6_UNBOUND);
713*7c478bd9Sstevel@tonic-gate 		}
714*7c478bd9Sstevel@tonic-gate 		if (msg != NULL) {
715*7c478bd9Sstevel@tonic-gate #ifdef DBG_DLPI
716*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "sending up %s\n",
717*7c478bd9Sstevel@tonic-gate 			    ((sap == PPP_IP) ? "PPP_LINKSTAT_IPV4_UNBOUND" :
718*7c478bd9Sstevel@tonic-gate 			    "PPP_LINKSTAT_IPV6_UNBOUND"));
719*7c478bd9Sstevel@tonic-gate #endif
720*7c478bd9Sstevel@tonic-gate 			putnext(ppa->ppa_ctl->sps_rq, msg);
721*7c478bd9Sstevel@tonic-gate 		}
722*7c478bd9Sstevel@tonic-gate 	}
723*7c478bd9Sstevel@tonic-gate 	DBGDLPI((CE_CONT, "/%d: unbound from sap %X (req %X)\n", sps->sps_mn_id,
724*7c478bd9Sstevel@tonic-gate 	    sps->sps_sap, sps->sps_req_sap));
725*7c478bd9Sstevel@tonic-gate 	sps->sps_req_sap = 0;
726*7c478bd9Sstevel@tonic-gate 	sps->sps_sap = -1;
727*7c478bd9Sstevel@tonic-gate 	sps->sps_dlstate = DL_UNBOUND;
728*7c478bd9Sstevel@tonic-gate 
729*7c478bd9Sstevel@tonic-gate 	dlokack(q, mp, DL_UNBIND_REQ);
730*7c478bd9Sstevel@tonic-gate }
731*7c478bd9Sstevel@tonic-gate 
732*7c478bd9Sstevel@tonic-gate /*
733*7c478bd9Sstevel@tonic-gate  * sppp_dlinforeq()
734*7c478bd9Sstevel@tonic-gate  *
735*7c478bd9Sstevel@tonic-gate  * MT-Perimeters:
736*7c478bd9Sstevel@tonic-gate  *    shared inner, shared outer.
737*7c478bd9Sstevel@tonic-gate  *
738*7c478bd9Sstevel@tonic-gate  * Description:
739*7c478bd9Sstevel@tonic-gate  *    Perform DL_INFO_REQ request, called by sppp_mproto.
740*7c478bd9Sstevel@tonic-gate  */
741*7c478bd9Sstevel@tonic-gate static int
742*7c478bd9Sstevel@tonic-gate sppp_dlinforeq(queue_t *q, mblk_t *mp, spppstr_t *sps)
743*7c478bd9Sstevel@tonic-gate {
744*7c478bd9Sstevel@tonic-gate 	dl_info_ack_t	*dlip;
745*7c478bd9Sstevel@tonic-gate 	uint32_t	size;
746*7c478bd9Sstevel@tonic-gate 	uint32_t	addr_size;
747*7c478bd9Sstevel@tonic-gate 	sppa_t		*ppa;
748*7c478bd9Sstevel@tonic-gate 
749*7c478bd9Sstevel@tonic-gate 	ASSERT(q != NULL && q->q_ptr != NULL);
750*7c478bd9Sstevel@tonic-gate 	ASSERT(mp != NULL && mp->b_rptr != NULL);
751*7c478bd9Sstevel@tonic-gate 	ASSERT(sps != NULL);
752*7c478bd9Sstevel@tonic-gate 	ppa = sps->sps_ppa;
753*7c478bd9Sstevel@tonic-gate 
754*7c478bd9Sstevel@tonic-gate 	/* Exchange current msg for a DL_INFO_ACK. */
755*7c478bd9Sstevel@tonic-gate 	addr_size = SPPP_ADDRL;
756*7c478bd9Sstevel@tonic-gate 	size = sizeof (dl_info_ack_t) + addr_size;
757*7c478bd9Sstevel@tonic-gate 	if ((mp = mexchange(q, mp, size, M_PCPROTO, DL_INFO_ACK)) == NULL) {
758*7c478bd9Sstevel@tonic-gate 		DBGERROR((CE_CONT, "DLPI info: mexchange failed\n"));
759*7c478bd9Sstevel@tonic-gate 		/* mexchange already sent up an merror ENOSR */
760*7c478bd9Sstevel@tonic-gate 		return (0);
761*7c478bd9Sstevel@tonic-gate 	}
762*7c478bd9Sstevel@tonic-gate 	/* Fill in DL_INFO_ACK fields and reply */
763*7c478bd9Sstevel@tonic-gate 	dlip = (dl_info_ack_t *)mp->b_rptr;
764*7c478bd9Sstevel@tonic-gate 	*dlip = sppp_infoack;
765*7c478bd9Sstevel@tonic-gate 	dlip->dl_current_state = sps->sps_dlstate;
766*7c478bd9Sstevel@tonic-gate 	dlip->dl_max_sdu = ppa != NULL ? ppa->ppa_mtu : PPP_MAXMTU;
767*7c478bd9Sstevel@tonic-gate #ifdef DBG_DLPI
768*7c478bd9Sstevel@tonic-gate 	{
769*7c478bd9Sstevel@tonic-gate 		const char *cp = state2name(dlip->dl_current_state);
770*7c478bd9Sstevel@tonic-gate 		if (cp != NULL)
771*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "info returns state %s, max sdu %d\n",
772*7c478bd9Sstevel@tonic-gate 			    cp, dlip->dl_max_sdu);
773*7c478bd9Sstevel@tonic-gate 		else
774*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "info returns state %d, max sdu %d\n",
775*7c478bd9Sstevel@tonic-gate 			    dlip->dl_current_state, dlip->dl_max_sdu);
776*7c478bd9Sstevel@tonic-gate 	}
777*7c478bd9Sstevel@tonic-gate #endif
778*7c478bd9Sstevel@tonic-gate 	qreply(q, mp);
779*7c478bd9Sstevel@tonic-gate 	return (0);
780*7c478bd9Sstevel@tonic-gate }
781*7c478bd9Sstevel@tonic-gate 
782*7c478bd9Sstevel@tonic-gate /*
783*7c478bd9Sstevel@tonic-gate  * sppp_dlunitdatareq()
784*7c478bd9Sstevel@tonic-gate  *
785*7c478bd9Sstevel@tonic-gate  * MT-Perimeters:
786*7c478bd9Sstevel@tonic-gate  *    shared inner, shared outer.
787*7c478bd9Sstevel@tonic-gate  *
788*7c478bd9Sstevel@tonic-gate  * Description:
789*7c478bd9Sstevel@tonic-gate  *    Handle DL_UNITDATA_REQ request, called by sppp_mproto. This procedure
790*7c478bd9Sstevel@tonic-gate  *    gets called for M_PROTO (DLPI) style of transmission. The fact that we
791*7c478bd9Sstevel@tonic-gate  *    have acknowledged IP's fastpath probing (DL_IOC_HDR_INFO) does not
792*7c478bd9Sstevel@tonic-gate  *    guarantee that IP will always transmit via M_DATA, and it merely implies
793*7c478bd9Sstevel@tonic-gate  *    that such situation _may_ happen. In other words, IP may decide to use
794*7c478bd9Sstevel@tonic-gate  *    M_PROTO (DLPI) for data transmission should it decide to do so.
795*7c478bd9Sstevel@tonic-gate  *    Therefore, we should never place any restrictions or checks against
796*7c478bd9Sstevel@tonic-gate  *    streams marked with SPS_FASTPATH, since it is legal for this procedure
797*7c478bd9Sstevel@tonic-gate  *    to be entered with or without the bit set.
798*7c478bd9Sstevel@tonic-gate  */
799*7c478bd9Sstevel@tonic-gate static int
800*7c478bd9Sstevel@tonic-gate sppp_dlunitdatareq(queue_t *q, mblk_t *mp, spppstr_t *sps)
801*7c478bd9Sstevel@tonic-gate {
802*7c478bd9Sstevel@tonic-gate 	sppa_t		*ppa;
803*7c478bd9Sstevel@tonic-gate 	mblk_t		*hdrmp;
804*7c478bd9Sstevel@tonic-gate 	mblk_t		*pktmp;
805*7c478bd9Sstevel@tonic-gate 	dl_unitdata_req_t *dludp;
806*7c478bd9Sstevel@tonic-gate 	int		dladdroff;
807*7c478bd9Sstevel@tonic-gate 	int		dladdrlen;
808*7c478bd9Sstevel@tonic-gate 	int		msize;
809*7c478bd9Sstevel@tonic-gate 	int		error = 0;
810*7c478bd9Sstevel@tonic-gate 	boolean_t	is_promisc;
811*7c478bd9Sstevel@tonic-gate 
812*7c478bd9Sstevel@tonic-gate 	ASSERT(q != NULL && q->q_ptr != NULL);
813*7c478bd9Sstevel@tonic-gate 	ASSERT(mp != NULL && mp->b_rptr != NULL);
814*7c478bd9Sstevel@tonic-gate 	ASSERT((MTYPE(mp) == M_PCPROTO) || (MTYPE(mp) == M_PROTO));
815*7c478bd9Sstevel@tonic-gate 	dludp = (dl_unitdata_req_t *)mp->b_rptr;
816*7c478bd9Sstevel@tonic-gate 	dladdroff = dludp->dl_dest_addr_offset;
817*7c478bd9Sstevel@tonic-gate 	dladdrlen = dludp->dl_dest_addr_length;
818*7c478bd9Sstevel@tonic-gate 	ASSERT(sps != NULL);
819*7c478bd9Sstevel@tonic-gate 	ASSERT(!IS_SPS_PIOATTACH(sps));
820*7c478bd9Sstevel@tonic-gate 	ASSERT(sps->sps_dlstate == DL_IDLE);
821*7c478bd9Sstevel@tonic-gate 	ASSERT(q->q_ptr == sps);
822*7c478bd9Sstevel@tonic-gate 	/*
823*7c478bd9Sstevel@tonic-gate 	 * If this stream is not attached to any ppas, then discard data
824*7c478bd9Sstevel@tonic-gate 	 * coming down through this stream.
825*7c478bd9Sstevel@tonic-gate 	 */
826*7c478bd9Sstevel@tonic-gate 	ppa = sps->sps_ppa;
827*7c478bd9Sstevel@tonic-gate 	if (ppa == NULL) {
828*7c478bd9Sstevel@tonic-gate 		DBGERROR((CE_CONT, "DLPI unitdata: no attached ppa\n"));
829*7c478bd9Sstevel@tonic-gate 		error = ENOLINK;
830*7c478bd9Sstevel@tonic-gate 	} else if (mp->b_cont == NULL) {
831*7c478bd9Sstevel@tonic-gate 		DBGERROR((CE_CONT, "DLPI unitdata: missing data\n"));
832*7c478bd9Sstevel@tonic-gate 		error = EPROTO;
833*7c478bd9Sstevel@tonic-gate 	}
834*7c478bd9Sstevel@tonic-gate 	if (error != 0) {
835*7c478bd9Sstevel@tonic-gate 		dluderrorind(q, mp, mp->b_rptr + dladdroff, dladdrlen,
836*7c478bd9Sstevel@tonic-gate 		    DL_BADDATA, error);
837*7c478bd9Sstevel@tonic-gate 		return (0);
838*7c478bd9Sstevel@tonic-gate 	}
839*7c478bd9Sstevel@tonic-gate 	ASSERT(mp->b_cont->b_rptr != NULL);
840*7c478bd9Sstevel@tonic-gate 	/*
841*7c478bd9Sstevel@tonic-gate 	 * Check if outgoing packet size is larger than allowed. We use
842*7c478bd9Sstevel@tonic-gate 	 * msgdsize to count all of M_DATA blocks in the message.
843*7c478bd9Sstevel@tonic-gate 	 */
844*7c478bd9Sstevel@tonic-gate 	msize = msgdsize(mp);
845*7c478bd9Sstevel@tonic-gate 	if (msize > ppa->ppa_mtu) {
846*7c478bd9Sstevel@tonic-gate 		/* Log, and send it anyway */
847*7c478bd9Sstevel@tonic-gate 		mutex_enter(&ppa->ppa_sta_lock);
848*7c478bd9Sstevel@tonic-gate 		ppa->ppa_otoolongs++;
849*7c478bd9Sstevel@tonic-gate 		mutex_exit(&ppa->ppa_sta_lock);
850*7c478bd9Sstevel@tonic-gate 	}
851*7c478bd9Sstevel@tonic-gate 	if (IS_SPS_KDEBUG(sps)) {
852*7c478bd9Sstevel@tonic-gate 		SPDEBUG(PPP_DRV_NAME
853*7c478bd9Sstevel@tonic-gate 		    "/%d: DL_UNITDATA_REQ (%d bytes) sps=0x%p flags=0x%b "
854*7c478bd9Sstevel@tonic-gate 		    "ppa=0x%p flags=0x%b\n", sps->sps_mn_id, msize,
855*7c478bd9Sstevel@tonic-gate 		    (void *)sps, sps->sps_flags, SPS_FLAGS_STR,
856*7c478bd9Sstevel@tonic-gate 		    (void *)ppa, ppa->ppa_flags, PPA_FLAGS_STR);
857*7c478bd9Sstevel@tonic-gate 	}
858*7c478bd9Sstevel@tonic-gate 	/* Allocate a message (M_DATA) to contain PPP header bytes. */
859*7c478bd9Sstevel@tonic-gate 	if ((hdrmp = allocb(PPP_HDRLEN, BPRI_MED)) == NULL) {
860*7c478bd9Sstevel@tonic-gate 		mutex_enter(&ppa->ppa_sta_lock);
861*7c478bd9Sstevel@tonic-gate 		ppa->ppa_allocbfail++;
862*7c478bd9Sstevel@tonic-gate 		mutex_exit(&ppa->ppa_sta_lock);
863*7c478bd9Sstevel@tonic-gate 		DBGERROR((CE_CONT,
864*7c478bd9Sstevel@tonic-gate 		    "DLPI unitdata: can't allocate header buffer\n"));
865*7c478bd9Sstevel@tonic-gate 		dluderrorind(q, mp, mp->b_rptr + dladdroff, dladdrlen,
866*7c478bd9Sstevel@tonic-gate 		    DL_SYSERR, ENOSR);
867*7c478bd9Sstevel@tonic-gate 		return (0);
868*7c478bd9Sstevel@tonic-gate 	}
869*7c478bd9Sstevel@tonic-gate 	/*
870*7c478bd9Sstevel@tonic-gate 	 * Should there be any promiscuous stream(s), send the data up
871*7c478bd9Sstevel@tonic-gate 	 * for each promiscuous stream that we recognize.
872*7c478bd9Sstevel@tonic-gate 	 */
873*7c478bd9Sstevel@tonic-gate 	rw_enter(&ppa->ppa_sib_lock, RW_READER);
874*7c478bd9Sstevel@tonic-gate 	is_promisc = ppa->ppa_promicnt;
875*7c478bd9Sstevel@tonic-gate 	if (is_promisc) {
876*7c478bd9Sstevel@tonic-gate 		ASSERT(ppa->ppa_streams != NULL);
877*7c478bd9Sstevel@tonic-gate 		sppp_dlprsendup(ppa->ppa_streams, mp->b_cont, sps->sps_sap,
878*7c478bd9Sstevel@tonic-gate 		    B_FALSE);
879*7c478bd9Sstevel@tonic-gate 	}
880*7c478bd9Sstevel@tonic-gate 	rw_exit(&ppa->ppa_sib_lock);
881*7c478bd9Sstevel@tonic-gate 	/* Discard DLPI header and keep only IP payload (mp->b_cont). */
882*7c478bd9Sstevel@tonic-gate 	pktmp = mp->b_cont;
883*7c478bd9Sstevel@tonic-gate 	mp->b_cont = NULL;
884*7c478bd9Sstevel@tonic-gate 	freemsg(mp);
885*7c478bd9Sstevel@tonic-gate 	mp = hdrmp;
886*7c478bd9Sstevel@tonic-gate 
887*7c478bd9Sstevel@tonic-gate 	*(uchar_t *)mp->b_wptr++ = PPP_ALLSTATIONS;
888*7c478bd9Sstevel@tonic-gate 	*(uchar_t *)mp->b_wptr++ = PPP_UI;
889*7c478bd9Sstevel@tonic-gate 	*(uchar_t *)mp->b_wptr++ = ((uint16_t)sps->sps_sap >> 8) & 0xff;
890*7c478bd9Sstevel@tonic-gate 	*(uchar_t *)mp->b_wptr++ = ((uint16_t)sps->sps_sap) & 0xff;
891*7c478bd9Sstevel@tonic-gate 	ASSERT(MBLKL(mp) == PPP_HDRLEN);
892*7c478bd9Sstevel@tonic-gate 
893*7c478bd9Sstevel@tonic-gate 	linkb(mp, pktmp);
894*7c478bd9Sstevel@tonic-gate 	/*
895*7c478bd9Sstevel@tonic-gate 	 * Only time-stamp the packet with hrtime if the upper stream
896*7c478bd9Sstevel@tonic-gate 	 * is configured to do so.
897*7c478bd9Sstevel@tonic-gate 	 */
898*7c478bd9Sstevel@tonic-gate 	if (IS_PPA_TIMESTAMP(ppa)) {
899*7c478bd9Sstevel@tonic-gate 		ppa->ppa_lasttx = gethrtime();
900*7c478bd9Sstevel@tonic-gate 	}
901*7c478bd9Sstevel@tonic-gate 	/*
902*7c478bd9Sstevel@tonic-gate 	 * Just put this back on the queue and allow the write service
903*7c478bd9Sstevel@tonic-gate 	 * routine to handle it.  We're nested too deeply here to
904*7c478bd9Sstevel@tonic-gate 	 * rewind the stack sufficiently to prevent overflow.  This is
905*7c478bd9Sstevel@tonic-gate 	 * the slow path anyway.
906*7c478bd9Sstevel@tonic-gate 	 */
907*7c478bd9Sstevel@tonic-gate 	if (putq(q, mp) == 0) {
908*7c478bd9Sstevel@tonic-gate 		mutex_enter(&ppa->ppa_sta_lock);
909*7c478bd9Sstevel@tonic-gate 		ppa->ppa_oqdropped++;
910*7c478bd9Sstevel@tonic-gate 		mutex_exit(&ppa->ppa_sta_lock);
911*7c478bd9Sstevel@tonic-gate 		freemsg(mp);
912*7c478bd9Sstevel@tonic-gate 	} else {
913*7c478bd9Sstevel@tonic-gate 		qenable(q);
914*7c478bd9Sstevel@tonic-gate 	}
915*7c478bd9Sstevel@tonic-gate 	return (0);
916*7c478bd9Sstevel@tonic-gate }
917*7c478bd9Sstevel@tonic-gate 
918*7c478bd9Sstevel@tonic-gate /*
919*7c478bd9Sstevel@tonic-gate  * sppp_dlpromisconreq()
920*7c478bd9Sstevel@tonic-gate  *
921*7c478bd9Sstevel@tonic-gate  * MT-Perimeters:
922*7c478bd9Sstevel@tonic-gate  *    shared inner, shared outer.
923*7c478bd9Sstevel@tonic-gate  *
924*7c478bd9Sstevel@tonic-gate  * Description:
925*7c478bd9Sstevel@tonic-gate  *    Perform DL_PROMISCON_REQ request, called by sppp_mproto.
926*7c478bd9Sstevel@tonic-gate  */
927*7c478bd9Sstevel@tonic-gate static int
928*7c478bd9Sstevel@tonic-gate sppp_dlpromisconreq(queue_t *q, mblk_t *mp, spppstr_t *sps)
929*7c478bd9Sstevel@tonic-gate {
930*7c478bd9Sstevel@tonic-gate 	t_uscalar_t	level;
931*7c478bd9Sstevel@tonic-gate 
932*7c478bd9Sstevel@tonic-gate 	ASSERT(q != NULL && q->q_ptr != NULL);
933*7c478bd9Sstevel@tonic-gate 	ASSERT(mp != NULL && mp->b_rptr != NULL);
934*7c478bd9Sstevel@tonic-gate 	level = ((dl_promiscon_req_t *)mp->b_rptr)->dl_level;
935*7c478bd9Sstevel@tonic-gate 	ASSERT(sps != NULL);
936*7c478bd9Sstevel@tonic-gate 
937*7c478bd9Sstevel@tonic-gate 	/* snoop issues DL_PROMISCON_REQ more than once. */
938*7c478bd9Sstevel@tonic-gate 	if (IS_SPS_PROMISC(sps)) {
939*7c478bd9Sstevel@tonic-gate 		dlokack(q, mp, DL_PROMISCON_REQ);
940*7c478bd9Sstevel@tonic-gate 	} else if ((level != DL_PROMISC_PHYS) && (level != DL_PROMISC_SAP) &&
941*7c478bd9Sstevel@tonic-gate 	    (level != DL_PROMISC_MULTI)) {
942*7c478bd9Sstevel@tonic-gate 		DBGERROR((CE_CONT, "DLPI promiscon: bad level %d\n", level));
943*7c478bd9Sstevel@tonic-gate 		dlerrorack(q, mp, DL_PROMISCON_REQ, DL_NOTSUPPORTED, 0);
944*7c478bd9Sstevel@tonic-gate 	} else {
945*7c478bd9Sstevel@tonic-gate 		qwriter(q, mp, sppp_dl_promiscon, PERIM_INNER);
946*7c478bd9Sstevel@tonic-gate 	}
947*7c478bd9Sstevel@tonic-gate 	return (0);
948*7c478bd9Sstevel@tonic-gate }
949*7c478bd9Sstevel@tonic-gate 
950*7c478bd9Sstevel@tonic-gate /*
951*7c478bd9Sstevel@tonic-gate  * sppp_dl_promiscon()
952*7c478bd9Sstevel@tonic-gate  *
953*7c478bd9Sstevel@tonic-gate  * MT-Perimeters:
954*7c478bd9Sstevel@tonic-gate  *    exclusive inner, shared outer.
955*7c478bd9Sstevel@tonic-gate  *
956*7c478bd9Sstevel@tonic-gate  * Description:
957*7c478bd9Sstevel@tonic-gate  *    Called by qwriter (INNER) from sppp_dlpromisconreq as the result of
958*7c478bd9Sstevel@tonic-gate  *    receiving a DL_PROMISCON_REQ message.
959*7c478bd9Sstevel@tonic-gate  */
960*7c478bd9Sstevel@tonic-gate static void
961*7c478bd9Sstevel@tonic-gate sppp_dl_promiscon(queue_t *q, mblk_t *mp)
962*7c478bd9Sstevel@tonic-gate {
963*7c478bd9Sstevel@tonic-gate 	spppstr_t	*sps;
964*7c478bd9Sstevel@tonic-gate 	sppa_t		*ppa;
965*7c478bd9Sstevel@tonic-gate 
966*7c478bd9Sstevel@tonic-gate 	ASSERT(q != NULL && q->q_ptr != NULL);
967*7c478bd9Sstevel@tonic-gate 	sps = (spppstr_t *)q->q_ptr;
968*7c478bd9Sstevel@tonic-gate 	ASSERT(!IS_SPS_PROMISC(sps));
969*7c478bd9Sstevel@tonic-gate 	ASSERT(mp != NULL && mp->b_rptr != NULL);
970*7c478bd9Sstevel@tonic-gate 	ppa = sps->sps_ppa;
971*7c478bd9Sstevel@tonic-gate 
972*7c478bd9Sstevel@tonic-gate 	sps->sps_flags |= SPS_PROMISC;
973*7c478bd9Sstevel@tonic-gate 	/*
974*7c478bd9Sstevel@tonic-gate 	 * We can't be sure that the sps_ppa field is valid, since the DLPI
975*7c478bd9Sstevel@tonic-gate 	 * spec says that DL_PROMISCON_REQ can be issued at any state, i.e.,
976*7c478bd9Sstevel@tonic-gate 	 * the request can be issued even before DL_ATTACH_REQ or PPPIO_ATTACH
977*7c478bd9Sstevel@tonic-gate 	 * be issued to associate this stream with a ppa.
978*7c478bd9Sstevel@tonic-gate 	 */
979*7c478bd9Sstevel@tonic-gate 	if (ppa != NULL) {
980*7c478bd9Sstevel@tonic-gate 		rw_enter(&ppa->ppa_sib_lock, RW_WRITER);
981*7c478bd9Sstevel@tonic-gate 		ppa->ppa_promicnt++;
982*7c478bd9Sstevel@tonic-gate 		rw_exit(&ppa->ppa_sib_lock);
983*7c478bd9Sstevel@tonic-gate 	}
984*7c478bd9Sstevel@tonic-gate 	DBGDLPI((CE_CONT, "/%d: promiscuous mode on\n", sps->sps_mn_id));
985*7c478bd9Sstevel@tonic-gate 	dlokack(q, mp, DL_PROMISCON_REQ);
986*7c478bd9Sstevel@tonic-gate }
987*7c478bd9Sstevel@tonic-gate 
988*7c478bd9Sstevel@tonic-gate /*
989*7c478bd9Sstevel@tonic-gate  * sppp_dlpromiscoffreq()
990*7c478bd9Sstevel@tonic-gate  *
991*7c478bd9Sstevel@tonic-gate  * MT-Perimeters:
992*7c478bd9Sstevel@tonic-gate  *    shared inner, shared outer.
993*7c478bd9Sstevel@tonic-gate  *
994*7c478bd9Sstevel@tonic-gate  * Description:
995*7c478bd9Sstevel@tonic-gate  *    Perform DL_PROMISCOFF_REQ request, called by sppp_mproto.
996*7c478bd9Sstevel@tonic-gate  */
997*7c478bd9Sstevel@tonic-gate static int
998*7c478bd9Sstevel@tonic-gate sppp_dlpromiscoffreq(queue_t *q, mblk_t *mp, spppstr_t *sps)
999*7c478bd9Sstevel@tonic-gate {
1000*7c478bd9Sstevel@tonic-gate 	t_uscalar_t	level;
1001*7c478bd9Sstevel@tonic-gate 
1002*7c478bd9Sstevel@tonic-gate 	ASSERT(q != NULL && q->q_ptr != NULL);
1003*7c478bd9Sstevel@tonic-gate 	ASSERT(mp != NULL && mp->b_rptr != NULL);
1004*7c478bd9Sstevel@tonic-gate 	level = ((dl_promiscoff_req_t *)mp->b_rptr)->dl_level;
1005*7c478bd9Sstevel@tonic-gate 	ASSERT(sps != NULL);
1006*7c478bd9Sstevel@tonic-gate 
1007*7c478bd9Sstevel@tonic-gate 	if (!IS_SPS_PROMISC(sps)) {
1008*7c478bd9Sstevel@tonic-gate 		DBGERROR((CE_CONT, "DLPI promiscoff: not promiscuous\n"));
1009*7c478bd9Sstevel@tonic-gate 		dlerrorack(q, mp, DL_PROMISCOFF_REQ, DL_NOTENAB, 0);
1010*7c478bd9Sstevel@tonic-gate 	} else if ((level != DL_PROMISC_PHYS) && (level != DL_PROMISC_SAP) &&
1011*7c478bd9Sstevel@tonic-gate 	    (level != DL_PROMISC_MULTI)) {
1012*7c478bd9Sstevel@tonic-gate 		dlerrorack(q, mp, DL_PROMISCOFF_REQ, DL_NOTSUPPORTED, 0);
1013*7c478bd9Sstevel@tonic-gate 		DBGERROR((CE_CONT, "DLPI promiscoff: bad level %d\n", level));
1014*7c478bd9Sstevel@tonic-gate 	} else {
1015*7c478bd9Sstevel@tonic-gate 		qwriter(q, mp, sppp_dl_promiscoff, PERIM_INNER);
1016*7c478bd9Sstevel@tonic-gate 	}
1017*7c478bd9Sstevel@tonic-gate 	return (0);
1018*7c478bd9Sstevel@tonic-gate 
1019*7c478bd9Sstevel@tonic-gate }
1020*7c478bd9Sstevel@tonic-gate 
1021*7c478bd9Sstevel@tonic-gate /*
1022*7c478bd9Sstevel@tonic-gate  * sppp_dl_promiscoff()
1023*7c478bd9Sstevel@tonic-gate  *
1024*7c478bd9Sstevel@tonic-gate  * MT-Perimeters:
1025*7c478bd9Sstevel@tonic-gate  *    exclusive inner, shared outer.
1026*7c478bd9Sstevel@tonic-gate  *
1027*7c478bd9Sstevel@tonic-gate  * Description:
1028*7c478bd9Sstevel@tonic-gate  *    Called by qwriter (INNER) from sppp_dlpromiscoffreq as the result of
1029*7c478bd9Sstevel@tonic-gate  *    receiving a DL_PROMISCOFF_REQ message.
1030*7c478bd9Sstevel@tonic-gate  */
1031*7c478bd9Sstevel@tonic-gate static void
1032*7c478bd9Sstevel@tonic-gate sppp_dl_promiscoff(queue_t *q, mblk_t *mp)
1033*7c478bd9Sstevel@tonic-gate {
1034*7c478bd9Sstevel@tonic-gate 	spppstr_t	*sps;
1035*7c478bd9Sstevel@tonic-gate 	sppa_t		*ppa;
1036*7c478bd9Sstevel@tonic-gate 
1037*7c478bd9Sstevel@tonic-gate 	ASSERT(q != NULL && q->q_ptr != NULL);
1038*7c478bd9Sstevel@tonic-gate 	sps = (spppstr_t *)q->q_ptr;
1039*7c478bd9Sstevel@tonic-gate 	ASSERT(IS_SPS_PROMISC(sps));
1040*7c478bd9Sstevel@tonic-gate 	ASSERT(mp != NULL && mp->b_rptr != NULL);
1041*7c478bd9Sstevel@tonic-gate 	ppa = sps->sps_ppa;
1042*7c478bd9Sstevel@tonic-gate 
1043*7c478bd9Sstevel@tonic-gate 	sps->sps_flags &= ~SPS_PROMISC;
1044*7c478bd9Sstevel@tonic-gate 	/*
1045*7c478bd9Sstevel@tonic-gate 	 * We can't be guaranteed that the sps_ppa field is still valid, since
1046*7c478bd9Sstevel@tonic-gate 	 * the control stream might have been closed earlier, in which case
1047*7c478bd9Sstevel@tonic-gate 	 * the close procedure would have NULL'd out the sps_ppa.
1048*7c478bd9Sstevel@tonic-gate 	 */
1049*7c478bd9Sstevel@tonic-gate 	if (ppa != NULL) {
1050*7c478bd9Sstevel@tonic-gate 		rw_enter(&ppa->ppa_sib_lock, RW_WRITER);
1051*7c478bd9Sstevel@tonic-gate 		ASSERT(ppa->ppa_promicnt > 0);
1052*7c478bd9Sstevel@tonic-gate 		ppa->ppa_promicnt--;
1053*7c478bd9Sstevel@tonic-gate 		rw_exit(&ppa->ppa_sib_lock);
1054*7c478bd9Sstevel@tonic-gate 	}
1055*7c478bd9Sstevel@tonic-gate 	DBGDLPI((CE_CONT, "/%d: promiscuous mode off\n", sps->sps_mn_id));
1056*7c478bd9Sstevel@tonic-gate 	dlokack(q, mp, DL_PROMISCOFF_REQ);
1057*7c478bd9Sstevel@tonic-gate }
1058*7c478bd9Sstevel@tonic-gate 
1059*7c478bd9Sstevel@tonic-gate /*
1060*7c478bd9Sstevel@tonic-gate  * sppp_dlphyreq()
1061*7c478bd9Sstevel@tonic-gate  *
1062*7c478bd9Sstevel@tonic-gate  * MT-Perimeters:
1063*7c478bd9Sstevel@tonic-gate  *    shared inner, shared outer.
1064*7c478bd9Sstevel@tonic-gate  *
1065*7c478bd9Sstevel@tonic-gate  * Description:
1066*7c478bd9Sstevel@tonic-gate  *    Perform DL_PHYS_ADDR_REQ request, called by sppp_mproto. This doesn't
1067*7c478bd9Sstevel@tonic-gate  *    return anything useful, but it keeps ifconfig happy.
1068*7c478bd9Sstevel@tonic-gate  */
1069*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
1070*7c478bd9Sstevel@tonic-gate static int
1071*7c478bd9Sstevel@tonic-gate sppp_dlphyreq(queue_t *q, mblk_t *mp, spppstr_t *us)
1072*7c478bd9Sstevel@tonic-gate {
1073*7c478bd9Sstevel@tonic-gate 	static struct ether_addr addr = { 0 };
1074*7c478bd9Sstevel@tonic-gate 
1075*7c478bd9Sstevel@tonic-gate 	dlphysaddrack(q, mp, (char *)&addr, ETHERADDRL);
1076*7c478bd9Sstevel@tonic-gate 	return (0);
1077*7c478bd9Sstevel@tonic-gate }
1078*7c478bd9Sstevel@tonic-gate 
1079*7c478bd9Sstevel@tonic-gate /*
1080*7c478bd9Sstevel@tonic-gate  * sppp_dladdether()
1081*7c478bd9Sstevel@tonic-gate  *
1082*7c478bd9Sstevel@tonic-gate  * Description:
1083*7c478bd9Sstevel@tonic-gate  *    Prepend an empty Ethernet header to msg for snoop, et al. Free
1084*7c478bd9Sstevel@tonic-gate  *    the original mblk if alloc fails. Only called for the purpose of sending
1085*7c478bd9Sstevel@tonic-gate  *    packets up the promiscous stream.
1086*7c478bd9Sstevel@tonic-gate  */
1087*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
1088*7c478bd9Sstevel@tonic-gate static mblk_t *
1089*7c478bd9Sstevel@tonic-gate sppp_dladdether(spppstr_t *sps, mblk_t *mp, t_scalar_t proto)
1090*7c478bd9Sstevel@tonic-gate {
1091*7c478bd9Sstevel@tonic-gate 	mblk_t		*eh;
1092*7c478bd9Sstevel@tonic-gate 	t_scalar_t	type;
1093*7c478bd9Sstevel@tonic-gate 
1094*7c478bd9Sstevel@tonic-gate 	if ((eh = allocb(sizeof (struct ether_header), BPRI_MED)) == NULL) {
1095*7c478bd9Sstevel@tonic-gate 		freemsg(mp);
1096*7c478bd9Sstevel@tonic-gate 		return (NULL);
1097*7c478bd9Sstevel@tonic-gate 	}
1098*7c478bd9Sstevel@tonic-gate 	if (proto == PPP_IP) {
1099*7c478bd9Sstevel@tonic-gate 		type = ETHERTYPE_IP;
1100*7c478bd9Sstevel@tonic-gate 	} else if (proto == PPP_IPV6) {
1101*7c478bd9Sstevel@tonic-gate 		type = ETHERTYPE_IPV6;
1102*7c478bd9Sstevel@tonic-gate 	} else {
1103*7c478bd9Sstevel@tonic-gate 		/*
1104*7c478bd9Sstevel@tonic-gate 		 * For all other protocols, end this up as an ETHERTYPE_PPP
1105*7c478bd9Sstevel@tonic-gate 		 * type of packet. Since we've skipped the PPP headers in the
1106*7c478bd9Sstevel@tonic-gate 		 * caller, make sure that we restore it. We know for sure that
1107*7c478bd9Sstevel@tonic-gate 		 * the PPP header still exists in the message (only skipped),
1108*7c478bd9Sstevel@tonic-gate 		 * since the sender of this message is pppd and it must have
1109*7c478bd9Sstevel@tonic-gate 		 * included the PPP header in front.
1110*7c478bd9Sstevel@tonic-gate 		 */
1111*7c478bd9Sstevel@tonic-gate 		type = ETHERTYPE_PPP;
1112*7c478bd9Sstevel@tonic-gate 		mp->b_rptr -= PPP_HDRLEN;
1113*7c478bd9Sstevel@tonic-gate 		ASSERT(mp->b_rptr >= mp->b_datap->db_base);
1114*7c478bd9Sstevel@tonic-gate 	}
1115*7c478bd9Sstevel@tonic-gate 	eh->b_wptr += sizeof (struct ether_header);
1116*7c478bd9Sstevel@tonic-gate 	bzero((caddr_t)eh->b_rptr, sizeof (struct ether_header));
1117*7c478bd9Sstevel@tonic-gate 	((struct ether_header *)eh->b_rptr)->ether_type = htons((int16_t)type);
1118*7c478bd9Sstevel@tonic-gate 
1119*7c478bd9Sstevel@tonic-gate 	linkb(eh, mp);
1120*7c478bd9Sstevel@tonic-gate 	return (eh);
1121*7c478bd9Sstevel@tonic-gate }
1122*7c478bd9Sstevel@tonic-gate 
1123*7c478bd9Sstevel@tonic-gate /*
1124*7c478bd9Sstevel@tonic-gate  * sppp_dladdud()
1125*7c478bd9Sstevel@tonic-gate  *
1126*7c478bd9Sstevel@tonic-gate  * Description:
1127*7c478bd9Sstevel@tonic-gate  *    Prepend DL_UNITDATA_IND mblk to msg, free original alloc fails.
1128*7c478bd9Sstevel@tonic-gate  */
1129*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
1130*7c478bd9Sstevel@tonic-gate mblk_t *
1131*7c478bd9Sstevel@tonic-gate sppp_dladdud(spppstr_t *sps, mblk_t *mp, t_scalar_t proto, boolean_t promisc)
1132*7c478bd9Sstevel@tonic-gate {
1133*7c478bd9Sstevel@tonic-gate 	dl_unitdata_ind_t *dlu;
1134*7c478bd9Sstevel@tonic-gate 	mblk_t		*dh;
1135*7c478bd9Sstevel@tonic-gate 	size_t		size;
1136*7c478bd9Sstevel@tonic-gate 	t_scalar_t	type;
1137*7c478bd9Sstevel@tonic-gate 
1138*7c478bd9Sstevel@tonic-gate 	size = sizeof (dl_unitdata_ind_t) + (2 * SPPP_ADDRL);
1139*7c478bd9Sstevel@tonic-gate 	if ((dh = allocb(size, BPRI_MED)) == NULL) {
1140*7c478bd9Sstevel@tonic-gate 		freemsg(mp);
1141*7c478bd9Sstevel@tonic-gate 		return (NULL);
1142*7c478bd9Sstevel@tonic-gate 	}
1143*7c478bd9Sstevel@tonic-gate 
1144*7c478bd9Sstevel@tonic-gate 	dh->b_datap->db_type = M_PROTO;
1145*7c478bd9Sstevel@tonic-gate 	dh->b_wptr = dh->b_datap->db_lim;
1146*7c478bd9Sstevel@tonic-gate 	dh->b_rptr = dh->b_wptr - size;
1147*7c478bd9Sstevel@tonic-gate 
1148*7c478bd9Sstevel@tonic-gate 	dlu = (dl_unitdata_ind_t *)dh->b_rptr;
1149*7c478bd9Sstevel@tonic-gate 	dlu->dl_primitive = DL_UNITDATA_IND;
1150*7c478bd9Sstevel@tonic-gate 	dlu->dl_dest_addr_length = SPPP_ADDRL;
1151*7c478bd9Sstevel@tonic-gate 	dlu->dl_dest_addr_offset = sizeof (dl_unitdata_ind_t);
1152*7c478bd9Sstevel@tonic-gate 	dlu->dl_src_addr_length = SPPP_ADDRL;
1153*7c478bd9Sstevel@tonic-gate 	dlu->dl_src_addr_offset = sizeof (dl_unitdata_ind_t) + SPPP_ADDRL;
1154*7c478bd9Sstevel@tonic-gate 	dlu->dl_group_address = 0;
1155*7c478bd9Sstevel@tonic-gate 
1156*7c478bd9Sstevel@tonic-gate 	if (promisc) {
1157*7c478bd9Sstevel@tonic-gate 		if (proto == PPP_IP) {
1158*7c478bd9Sstevel@tonic-gate 			type = ETHERTYPE_IP;
1159*7c478bd9Sstevel@tonic-gate 		} else if (proto == PPP_IPV6) {
1160*7c478bd9Sstevel@tonic-gate 			type = ETHERTYPE_IPV6;
1161*7c478bd9Sstevel@tonic-gate 		} else {
1162*7c478bd9Sstevel@tonic-gate 			/*
1163*7c478bd9Sstevel@tonic-gate 			 * For all other protocols, send this up as an
1164*7c478bd9Sstevel@tonic-gate 			 * ETHERTYPE_PPP type of packet. Since we've skipped
1165*7c478bd9Sstevel@tonic-gate 			 * the PPP headers in the caller, make sure that we
1166*7c478bd9Sstevel@tonic-gate 			 * restore it. We know for sure that the PPP header
1167*7c478bd9Sstevel@tonic-gate 			 * still exists in the message (only skipped), since
1168*7c478bd9Sstevel@tonic-gate 			 * the sender of this message is pppd and it must
1169*7c478bd9Sstevel@tonic-gate 			 * have included the PPP header in front.
1170*7c478bd9Sstevel@tonic-gate 			 */
1171*7c478bd9Sstevel@tonic-gate 			type = ETHERTYPE_PPP;
1172*7c478bd9Sstevel@tonic-gate 			mp->b_rptr -= PPP_HDRLEN;
1173*7c478bd9Sstevel@tonic-gate 			ASSERT(mp->b_rptr >= mp->b_datap->db_base);
1174*7c478bd9Sstevel@tonic-gate 		}
1175*7c478bd9Sstevel@tonic-gate 	} else {
1176*7c478bd9Sstevel@tonic-gate 		type = sps->sps_req_sap;
1177*7c478bd9Sstevel@tonic-gate 	}
1178*7c478bd9Sstevel@tonic-gate 	/*
1179*7c478bd9Sstevel@tonic-gate 	 * Send the DLPI client the data with the SAP they requested,
1180*7c478bd9Sstevel@tonic-gate 	 * (e.g. ETHERTYPE_IP) rather than the PPP protocol (e.g. PPP_IP).
1181*7c478bd9Sstevel@tonic-gate 	 */
1182*7c478bd9Sstevel@tonic-gate 	((spppreqsap_t *)(dlu + 1))[0] = type;
1183*7c478bd9Sstevel@tonic-gate 	((spppreqsap_t *)(dlu + 1))[1] = type;
1184*7c478bd9Sstevel@tonic-gate 
1185*7c478bd9Sstevel@tonic-gate 	linkb(dh, mp);
1186*7c478bd9Sstevel@tonic-gate 	return (dh);
1187*7c478bd9Sstevel@tonic-gate }
1188*7c478bd9Sstevel@tonic-gate 
1189*7c478bd9Sstevel@tonic-gate /*
1190*7c478bd9Sstevel@tonic-gate  * sppp_dlprsendup()
1191*7c478bd9Sstevel@tonic-gate  *
1192*7c478bd9Sstevel@tonic-gate  * Description:
1193*7c478bd9Sstevel@tonic-gate  *    For any valid promiscuous streams (marked with SPS_PROMISC and its
1194*7c478bd9Sstevel@tonic-gate  *    sps_dlstate is DL_IDLE), send data upstream. The caller is expected
1195*7c478bd9Sstevel@tonic-gate  *    to hold ppa_sib_lock when calling this procedure.
1196*7c478bd9Sstevel@tonic-gate  */
1197*7c478bd9Sstevel@tonic-gate void
1198*7c478bd9Sstevel@tonic-gate sppp_dlprsendup(spppstr_t *sps, mblk_t *mp, t_scalar_t proto, boolean_t header)
1199*7c478bd9Sstevel@tonic-gate {
1200*7c478bd9Sstevel@tonic-gate 	sppa_t	*ppa;
1201*7c478bd9Sstevel@tonic-gate 	mblk_t	*dmp;
1202*7c478bd9Sstevel@tonic-gate 
1203*7c478bd9Sstevel@tonic-gate 	ASSERT(sps != NULL);
1204*7c478bd9Sstevel@tonic-gate 	ASSERT(mp != NULL && mp->b_rptr != NULL);
1205*7c478bd9Sstevel@tonic-gate 	ppa = sps->sps_ppa;
1206*7c478bd9Sstevel@tonic-gate 	ASSERT(ppa != NULL);
1207*7c478bd9Sstevel@tonic-gate 
1208*7c478bd9Sstevel@tonic-gate 	/* NOTE: caller must hold ppa_sib_lock in RW_READER mode */
1209*7c478bd9Sstevel@tonic-gate 	ASSERT(RW_READ_HELD(&ppa->ppa_sib_lock));
1210*7c478bd9Sstevel@tonic-gate 
1211*7c478bd9Sstevel@tonic-gate 	for (; sps != NULL; sps = sps->sps_nextsib) {
1212*7c478bd9Sstevel@tonic-gate 		/*
1213*7c478bd9Sstevel@tonic-gate 		 * We specifically test to ensure that the DLPI state for the
1214*7c478bd9Sstevel@tonic-gate 		 * promiscous stream is IDLE (DL_IDLE), since such state tells
1215*7c478bd9Sstevel@tonic-gate 		 * us that the promiscous stream has been bound to PPP_ALLSAP.
1216*7c478bd9Sstevel@tonic-gate 		 */
1217*7c478bd9Sstevel@tonic-gate 		if (IS_SPS_PROMISC(sps) && (sps->sps_dlstate == DL_IDLE) &&
1218*7c478bd9Sstevel@tonic-gate 		    canputnext(sps->sps_rq)) {
1219*7c478bd9Sstevel@tonic-gate 			if ((dmp = dupmsg(mp)) == NULL) {
1220*7c478bd9Sstevel@tonic-gate 				mutex_enter(&ppa->ppa_sta_lock);
1221*7c478bd9Sstevel@tonic-gate 				ppa->ppa_allocbfail++;
1222*7c478bd9Sstevel@tonic-gate 				mutex_exit(&ppa->ppa_sta_lock);
1223*7c478bd9Sstevel@tonic-gate 				continue;
1224*7c478bd9Sstevel@tonic-gate 			}
1225*7c478bd9Sstevel@tonic-gate 			if (header) {
1226*7c478bd9Sstevel@tonic-gate 				dmp->b_rptr += PPP_HDRLEN;
1227*7c478bd9Sstevel@tonic-gate 			}
1228*7c478bd9Sstevel@tonic-gate 			if (IS_SPS_RAWDATA(sps)) {
1229*7c478bd9Sstevel@tonic-gate 				/* function frees original message if fails */
1230*7c478bd9Sstevel@tonic-gate 				dmp = sppp_dladdether(sps, dmp, proto);
1231*7c478bd9Sstevel@tonic-gate 			} else {
1232*7c478bd9Sstevel@tonic-gate 				/* function frees original message if fails */
1233*7c478bd9Sstevel@tonic-gate 				dmp = sppp_dladdud(sps, dmp, proto, B_TRUE);
1234*7c478bd9Sstevel@tonic-gate 			}
1235*7c478bd9Sstevel@tonic-gate 			if (dmp != NULL) {
1236*7c478bd9Sstevel@tonic-gate 				putnext(sps->sps_rq, dmp);
1237*7c478bd9Sstevel@tonic-gate 			} else {
1238*7c478bd9Sstevel@tonic-gate 				mutex_enter(&ppa->ppa_sta_lock);
1239*7c478bd9Sstevel@tonic-gate 				ppa->ppa_allocbfail++;
1240*7c478bd9Sstevel@tonic-gate 				mutex_exit(&ppa->ppa_sta_lock);
1241*7c478bd9Sstevel@tonic-gate 			}
1242*7c478bd9Sstevel@tonic-gate 		}
1243*7c478bd9Sstevel@tonic-gate 	}
1244*7c478bd9Sstevel@tonic-gate }
1245