xref: /onnv-gate/usr/src/uts/common/io/dld/dld_proto.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate /*
30*0Sstevel@tonic-gate  * Data-Link Driver
31*0Sstevel@tonic-gate  */
32*0Sstevel@tonic-gate 
33*0Sstevel@tonic-gate #include <sys/types.h>
34*0Sstevel@tonic-gate #include <sys/debug.h>
35*0Sstevel@tonic-gate #include <sys/sysmacros.h>
36*0Sstevel@tonic-gate #include <sys/stream.h>
37*0Sstevel@tonic-gate #include <sys/ddi.h>
38*0Sstevel@tonic-gate #include <sys/sunddi.h>
39*0Sstevel@tonic-gate #include <sys/strsun.h>
40*0Sstevel@tonic-gate #include <sys/dlpi.h>
41*0Sstevel@tonic-gate #include <netinet/in.h>
42*0Sstevel@tonic-gate #include <sys/sdt.h>
43*0Sstevel@tonic-gate #include <sys/strsubr.h>
44*0Sstevel@tonic-gate #include <sys/vlan.h>
45*0Sstevel@tonic-gate #include <sys/mac.h>
46*0Sstevel@tonic-gate #include <sys/dls.h>
47*0Sstevel@tonic-gate #include <sys/dld.h>
48*0Sstevel@tonic-gate #include <sys/dld_impl.h>
49*0Sstevel@tonic-gate 
50*0Sstevel@tonic-gate typedef boolean_t proto_reqfunc_t(dld_str_t *, union DL_primitives *, mblk_t *);
51*0Sstevel@tonic-gate 
52*0Sstevel@tonic-gate static proto_reqfunc_t proto_info_req, proto_attach_req, proto_detach_req,
53*0Sstevel@tonic-gate     proto_bind_req, proto_unbind_req, proto_promiscon_req, proto_promiscoff_req,
54*0Sstevel@tonic-gate     proto_enabmulti_req, proto_disabmulti_req, proto_physaddr_req,
55*0Sstevel@tonic-gate     proto_setphysaddr_req, proto_udqos_req, proto_req, proto_capability_req,
56*0Sstevel@tonic-gate     proto_notify_req, proto_unitdata_req, proto_passive_req;
57*0Sstevel@tonic-gate 
58*0Sstevel@tonic-gate static void		proto_excl(queue_t *, mblk_t *);
59*0Sstevel@tonic-gate static void		proto_info_ack(dld_str_t *, mblk_t *);
60*0Sstevel@tonic-gate static void		proto_attach_ack(dld_str_t *, mblk_t *, int);
61*0Sstevel@tonic-gate static void		proto_detach_ack(dld_str_t *, mblk_t *);
62*0Sstevel@tonic-gate static void		proto_bind_ack(dld_str_t *, mblk_t *, int);
63*0Sstevel@tonic-gate static void		proto_unbind_ack(dld_str_t *, mblk_t *);
64*0Sstevel@tonic-gate static void		proto_promiscon_ack(dld_str_t *, mblk_t *, int);
65*0Sstevel@tonic-gate static void		proto_promiscoff_ack(dld_str_t *, mblk_t *, int);
66*0Sstevel@tonic-gate static void		proto_enabmulti_ack(dld_str_t *, mblk_t *, int);
67*0Sstevel@tonic-gate static void		proto_disabmulti_ack(dld_str_t *, mblk_t *, int);
68*0Sstevel@tonic-gate static void		proto_setphysaddr_ack(dld_str_t *, mblk_t *, int);
69*0Sstevel@tonic-gate static void		proto_physaddr_ack(dld_str_t *, mblk_t *, t_uscalar_t);
70*0Sstevel@tonic-gate static void		proto_udqos_ack(dld_str_t *, mblk_t *);
71*0Sstevel@tonic-gate static void		proto_poll_disable(dld_str_t *);
72*0Sstevel@tonic-gate static boolean_t	proto_poll_enable(dld_str_t *, dl_capab_poll_t *);
73*0Sstevel@tonic-gate static void		proto_capability_ack(dld_str_t *, mblk_t *);
74*0Sstevel@tonic-gate static void		proto_capability_enable(dld_str_t *, mblk_t *);
75*0Sstevel@tonic-gate static void		proto_notify_ack(dld_str_t *, mblk_t *, uint_t,
76*0Sstevel@tonic-gate     uint_t);
77*0Sstevel@tonic-gate 
78*0Sstevel@tonic-gate #define	DL_SOLARIS	0x100
79*0Sstevel@tonic-gate 
80*0Sstevel@tonic-gate /*
81*0Sstevel@tonic-gate  * M_PROTO/M_PCPROTO request handlers
82*0Sstevel@tonic-gate  */
83*0Sstevel@tonic-gate 
84*0Sstevel@tonic-gate typedef struct proto_req_info {
85*0Sstevel@tonic-gate 	t_uscalar_t	pri_prim;
86*0Sstevel@tonic-gate 	const char	*pri_txt;
87*0Sstevel@tonic-gate 	boolean_t	pri_needexcl;
88*0Sstevel@tonic-gate 	boolean_t	pri_active;
89*0Sstevel@tonic-gate 	proto_reqfunc_t	*pri_fn;
90*0Sstevel@tonic-gate } proto_req_info_t;
91*0Sstevel@tonic-gate 
92*0Sstevel@tonic-gate static proto_req_info_t	proto_ri[] = {
93*0Sstevel@tonic-gate 	{ DL_INFO_REQ, "DL_INFO_REQ", B_FALSE, B_FALSE, proto_info_req },
94*0Sstevel@tonic-gate 	{ DL_BIND_REQ, "DL_BIND_REQ", B_TRUE, B_TRUE, proto_bind_req },
95*0Sstevel@tonic-gate 	{ DL_UNBIND_REQ, "DL_UNBIND_REQ", B_TRUE, B_FALSE, proto_unbind_req },
96*0Sstevel@tonic-gate 	{ DL_INFO_ACK, "DL_INFO_ACK", B_FALSE, B_FALSE, proto_req },
97*0Sstevel@tonic-gate 	{ DL_BIND_ACK, "DL_BIND_ACK", B_FALSE, B_FALSE, proto_req },
98*0Sstevel@tonic-gate 	{ DL_ERROR_ACK, "DL_ERROR_ACK", B_FALSE, B_FALSE, proto_req },
99*0Sstevel@tonic-gate 	{ DL_OK_ACK, "DL_OK_ACK", B_FALSE, B_FALSE, proto_req },
100*0Sstevel@tonic-gate 	{ DL_UNITDATA_REQ, "DL_UNITDATA_REQ", B_FALSE, B_FALSE,
101*0Sstevel@tonic-gate     proto_unitdata_req },
102*0Sstevel@tonic-gate 	{ DL_UNITDATA_IND, "DL_UNITDATA_IND", B_FALSE, B_FALSE, proto_req },
103*0Sstevel@tonic-gate 	{ DL_UDERROR_IND, "DL_UDERROR_IND", B_FALSE, B_FALSE, proto_req },
104*0Sstevel@tonic-gate 	{ DL_UDQOS_REQ, "DL_UDQOS_REQ", B_TRUE, B_FALSE, proto_udqos_req },
105*0Sstevel@tonic-gate 	{ DL_ATTACH_REQ, "DL_ATTACH_REQ", B_TRUE, B_FALSE, proto_attach_req },
106*0Sstevel@tonic-gate 	{ DL_DETACH_REQ, "DL_DETACH_REQ", B_TRUE, B_FALSE, proto_detach_req },
107*0Sstevel@tonic-gate 	{ DL_CONNECT_REQ, "DL_CONNECT_REQ", B_FALSE, B_FALSE, proto_req },
108*0Sstevel@tonic-gate 	{ DL_CONNECT_IND, "DL_CONNECT_IND", B_FALSE, B_FALSE, proto_req },
109*0Sstevel@tonic-gate 	{ DL_CONNECT_RES, "DL_CONNECT_RES", B_FALSE, B_FALSE, proto_req },
110*0Sstevel@tonic-gate 	{ DL_CONNECT_CON, "DL_CONNECT_CON", B_FALSE, B_FALSE, proto_req },
111*0Sstevel@tonic-gate 	{ DL_TOKEN_REQ, "DL_TOKEN_REQ", B_FALSE, B_FALSE, proto_req },
112*0Sstevel@tonic-gate 	{ DL_TOKEN_ACK, "DL_TOKEN_ACK", B_FALSE, B_FALSE, proto_req },
113*0Sstevel@tonic-gate 	{ DL_DISCONNECT_REQ, "DL_DISCONNECT_REQ", B_FALSE, B_FALSE, proto_req },
114*0Sstevel@tonic-gate 	{ DL_DISCONNECT_IND, "DL_DISCONNECT_IND", B_FALSE, B_FALSE, proto_req },
115*0Sstevel@tonic-gate 	{ DL_SUBS_UNBIND_REQ, "DL_SUBS_UNBIND_REQ", B_FALSE, B_FALSE,
116*0Sstevel@tonic-gate     proto_req },
117*0Sstevel@tonic-gate 	{ 0x16, "undefined", B_FALSE, B_FALSE, proto_req },
118*0Sstevel@tonic-gate 	{ DL_RESET_REQ, "DL_RESET_REQ", B_FALSE, B_FALSE, proto_req },
119*0Sstevel@tonic-gate 	{ DL_RESET_IND, "DL_RESET_IND", B_FALSE, B_FALSE, proto_req },
120*0Sstevel@tonic-gate 	{ DL_RESET_RES, "DL_RESET_RES", B_FALSE, B_FALSE, proto_req },
121*0Sstevel@tonic-gate 	{ DL_RESET_CON, "DL_RESET_CON", B_FALSE, B_FALSE, proto_req },
122*0Sstevel@tonic-gate 	{ DL_SUBS_BIND_REQ, "DL_SUBS_BIND_REQ", B_FALSE, B_FALSE, proto_req },
123*0Sstevel@tonic-gate 	{ DL_SUBS_BIND_ACK, "DL_SUBS_BIND_ACK", B_FALSE, B_FALSE, proto_req },
124*0Sstevel@tonic-gate 	{ DL_ENABMULTI_REQ, "DL_ENABMULTI_REQ", B_TRUE, B_TRUE,
125*0Sstevel@tonic-gate     proto_enabmulti_req },
126*0Sstevel@tonic-gate 	{ DL_DISABMULTI_REQ, "DL_DISABMULTI_REQ", B_TRUE, B_FALSE,
127*0Sstevel@tonic-gate     proto_disabmulti_req },
128*0Sstevel@tonic-gate 	{ DL_PROMISCON_REQ, "DL_PROMISCON_REQ", B_TRUE, B_TRUE,
129*0Sstevel@tonic-gate     proto_promiscon_req },
130*0Sstevel@tonic-gate 	{ DL_PROMISCOFF_REQ, "DL_PROMISCOFF_REQ", B_TRUE, B_FALSE,
131*0Sstevel@tonic-gate     proto_promiscoff_req },
132*0Sstevel@tonic-gate 	{ DL_DATA_ACK_REQ, "DL_DATA_ACK_REQ", B_FALSE, B_FALSE, proto_req },
133*0Sstevel@tonic-gate 	{ DL_DATA_ACK_IND, "DL_DATA_ACK_IND", B_FALSE, B_FALSE, proto_req },
134*0Sstevel@tonic-gate 	{ DL_DATA_ACK_STATUS_IND, "DL_DATA_ACK_STATUS_IND", B_FALSE, B_FALSE,
135*0Sstevel@tonic-gate     proto_req },
136*0Sstevel@tonic-gate 	{ DL_REPLY_REQ, "DL_REPLY_REQ", B_FALSE, B_FALSE, proto_req },
137*0Sstevel@tonic-gate 	{ DL_REPLY_IND, "DL_REPLY_IND", B_FALSE, B_FALSE, proto_req },
138*0Sstevel@tonic-gate 	{ DL_REPLY_STATUS_IND, "DL_REPLY_STATUS_IND", B_FALSE, B_FALSE,
139*0Sstevel@tonic-gate     proto_req },
140*0Sstevel@tonic-gate 	{ DL_REPLY_UPDATE_REQ, "DL_REPLY_UPDATE_REQ", B_FALSE, B_FALSE,
141*0Sstevel@tonic-gate     proto_req },
142*0Sstevel@tonic-gate 	{ DL_REPLY_UPDATE_STATUS_IND, "DL_REPLY_UPDATE_STATUS_IND", B_FALSE,
143*0Sstevel@tonic-gate     B_FALSE, proto_req },
144*0Sstevel@tonic-gate 	{ DL_XID_REQ, "DL_XID_REQ", B_FALSE, B_FALSE, proto_req },
145*0Sstevel@tonic-gate 	{ DL_XID_IND, "DL_XID_IND", B_FALSE, B_FALSE, proto_req },
146*0Sstevel@tonic-gate 	{ DL_XID_RES, "DL_XID_RES", B_FALSE, B_FALSE, proto_req },
147*0Sstevel@tonic-gate 	{ DL_XID_CON, "DL_XID_CON", B_FALSE, B_FALSE, proto_req },
148*0Sstevel@tonic-gate 	{ DL_TEST_REQ, "DL_TEST_REQ", B_FALSE, B_FALSE, proto_req },
149*0Sstevel@tonic-gate 	{ DL_TEST_IND, "DL_TEST_IND", B_FALSE, B_FALSE, proto_req },
150*0Sstevel@tonic-gate 	{ DL_TEST_RES, "DL_TEST_RES", B_FALSE, B_FALSE, proto_req },
151*0Sstevel@tonic-gate 	{ DL_TEST_CON, "DL_TEST_CON", B_FALSE, B_FALSE, proto_req },
152*0Sstevel@tonic-gate 	{ DL_PHYS_ADDR_REQ, "DL_PHYS_ADDR_REQ", B_FALSE, B_FALSE,
153*0Sstevel@tonic-gate     proto_physaddr_req },
154*0Sstevel@tonic-gate 	{ DL_PHYS_ADDR_ACK, "DL_PHYS_ADDR_ACK", B_FALSE, B_FALSE, proto_req },
155*0Sstevel@tonic-gate 	{ DL_SET_PHYS_ADDR_REQ, "DL_SET_PHYS_ADDR_REQ", B_TRUE, B_TRUE,
156*0Sstevel@tonic-gate     proto_setphysaddr_req },
157*0Sstevel@tonic-gate 	{ DL_GET_STATISTICS_REQ, "DL_GET_STATISTICS_REQ", B_FALSE, B_FALSE,
158*0Sstevel@tonic-gate     proto_req },
159*0Sstevel@tonic-gate 	{ DL_GET_STATISTICS_ACK, "DL_GET_STATISTICS_ACK", B_FALSE, B_FALSE,
160*0Sstevel@tonic-gate     proto_req }
161*0Sstevel@tonic-gate };
162*0Sstevel@tonic-gate 
163*0Sstevel@tonic-gate #define	PROTO_RI_COUNT	(sizeof (proto_ri) / sizeof (proto_ri[0]))
164*0Sstevel@tonic-gate 
165*0Sstevel@tonic-gate static proto_req_info_t	proto_sri[] = {
166*0Sstevel@tonic-gate 	{ DL_NOTIFY_REQ, "DL_NOTIFY_REQ", B_FALSE, B_FALSE, proto_notify_req },
167*0Sstevel@tonic-gate 	{ DL_NOTIFY_ACK, "DL_NOTIFY_ACK", B_FALSE, B_FALSE, proto_req },
168*0Sstevel@tonic-gate 	{ DL_NOTIFY_IND, "DL_NOTIFY_IND", B_FALSE, B_FALSE, proto_req },
169*0Sstevel@tonic-gate 	{ DL_AGGR_REQ, "DL_AGGR_REQ", B_FALSE, B_TRUE, proto_req },
170*0Sstevel@tonic-gate 	{ DL_AGGR_IND, "DL_AGGR_IND", B_FALSE, B_FALSE, proto_req },
171*0Sstevel@tonic-gate 	{ DL_UNAGGR_REQ, "DL_UNAGGR_REQ", B_FALSE, B_TRUE, proto_req },
172*0Sstevel@tonic-gate 	{ 0x106, "undefined", B_FALSE, B_FALSE, proto_req },
173*0Sstevel@tonic-gate 	{ 0x107, "undefined", B_FALSE, B_FALSE, proto_req },
174*0Sstevel@tonic-gate 	{ 0x108, "undefined", B_FALSE, B_FALSE, proto_req },
175*0Sstevel@tonic-gate 	{ 0x109, "undefined", B_FALSE, B_FALSE, proto_req },
176*0Sstevel@tonic-gate 	{ 0x10a, "undefined", B_FALSE, B_FALSE, proto_req },
177*0Sstevel@tonic-gate 	{ 0x10b, "undefined", B_FALSE, B_FALSE, proto_req },
178*0Sstevel@tonic-gate 	{ 0x10c, "undefined", B_FALSE, B_FALSE, proto_req },
179*0Sstevel@tonic-gate 	{ 0x10d, "undefined", B_FALSE, B_FALSE, proto_req },
180*0Sstevel@tonic-gate 	{ 0x10e, "undefined", B_FALSE, B_FALSE, proto_req },
181*0Sstevel@tonic-gate 	{ 0x10f, "undefined", B_FALSE, B_FALSE, proto_req },
182*0Sstevel@tonic-gate 	{ DL_CAPABILITY_REQ, "DL_CAPABILITY_REQ", B_FALSE, B_FALSE,
183*0Sstevel@tonic-gate     proto_capability_req },
184*0Sstevel@tonic-gate 	{ DL_CAPABILITY_ACK, "DL_CAPABILITY_ACK", B_FALSE, B_FALSE, proto_req },
185*0Sstevel@tonic-gate 	{ DL_CONTROL_REQ, "DL_CONTROL_REQ", B_FALSE, B_TRUE, proto_req },
186*0Sstevel@tonic-gate 	{ DL_CONTROL_ACK, "DL_CONTROL_ACK", B_FALSE, B_FALSE, proto_req },
187*0Sstevel@tonic-gate 	{ DL_PASSIVE_REQ, "DL_PASSIVE_REQ", B_TRUE, B_FALSE, proto_passive_req }
188*0Sstevel@tonic-gate };
189*0Sstevel@tonic-gate 
190*0Sstevel@tonic-gate #define	PROTO_SRI_COUNT	(sizeof (proto_sri) / sizeof (proto_sri[0]))
191*0Sstevel@tonic-gate 
192*0Sstevel@tonic-gate #define	DL_ACK_PENDING(state) \
193*0Sstevel@tonic-gate 	((state) == DL_ATTACH_PENDING || \
194*0Sstevel@tonic-gate 	(state) == DL_DETACH_PENDING || \
195*0Sstevel@tonic-gate 	(state) == DL_BIND_PENDING || \
196*0Sstevel@tonic-gate 	(state) == DL_UNBIND_PENDING)
197*0Sstevel@tonic-gate 
198*0Sstevel@tonic-gate /*
199*0Sstevel@tonic-gate  * Process a DLPI protocol message. (Only ever called from put(9e)).
200*0Sstevel@tonic-gate  */
201*0Sstevel@tonic-gate void
202*0Sstevel@tonic-gate dld_proto(dld_str_t *dsp, mblk_t *mp)
203*0Sstevel@tonic-gate {
204*0Sstevel@tonic-gate 	union DL_primitives	*udlp;
205*0Sstevel@tonic-gate 	t_uscalar_t		prim;
206*0Sstevel@tonic-gate 	proto_req_info_t	*prip;
207*0Sstevel@tonic-gate 	boolean_t		success;
208*0Sstevel@tonic-gate 
209*0Sstevel@tonic-gate 	if (MBLKL(mp) < sizeof (t_uscalar_t)) {
210*0Sstevel@tonic-gate 		freemsg(mp);
211*0Sstevel@tonic-gate 		return;
212*0Sstevel@tonic-gate 	}
213*0Sstevel@tonic-gate 
214*0Sstevel@tonic-gate 	udlp = (union DL_primitives *)mp->b_rptr;
215*0Sstevel@tonic-gate 	prim = udlp->dl_primitive;
216*0Sstevel@tonic-gate 
217*0Sstevel@tonic-gate 	/*
218*0Sstevel@tonic-gate 	 * Select the correct jump table.
219*0Sstevel@tonic-gate 	 */
220*0Sstevel@tonic-gate 	if (prim & DL_SOLARIS) {
221*0Sstevel@tonic-gate 		/*
222*0Sstevel@tonic-gate 		 * Entries in the 'solaris extensions' jump table
223*0Sstevel@tonic-gate 		 * have an extra bit in the primitive value. Clear it
224*0Sstevel@tonic-gate 		 * to do the lookup.
225*0Sstevel@tonic-gate 		 */
226*0Sstevel@tonic-gate 		prim &= ~DL_SOLARIS;
227*0Sstevel@tonic-gate 
228*0Sstevel@tonic-gate 		/*
229*0Sstevel@tonic-gate 		 * Check the primitive is in range.
230*0Sstevel@tonic-gate 		 */
231*0Sstevel@tonic-gate 		if (prim >= PROTO_SRI_COUNT)
232*0Sstevel@tonic-gate 			goto unsupported;
233*0Sstevel@tonic-gate 
234*0Sstevel@tonic-gate 		/*
235*0Sstevel@tonic-gate 		 * Grab the jump table entry.
236*0Sstevel@tonic-gate 		 */
237*0Sstevel@tonic-gate 		prip = &proto_sri[prim];
238*0Sstevel@tonic-gate 
239*0Sstevel@tonic-gate 		/*
240*0Sstevel@tonic-gate 		 * OR the cleared bit back in to make the primitive valid
241*0Sstevel@tonic-gate 		 * again.
242*0Sstevel@tonic-gate 		 */
243*0Sstevel@tonic-gate 		prim |= DL_SOLARIS;
244*0Sstevel@tonic-gate 	} else {
245*0Sstevel@tonic-gate 		/*
246*0Sstevel@tonic-gate 		 * Check the primitive is in range.
247*0Sstevel@tonic-gate 		 */
248*0Sstevel@tonic-gate 		if (prim >= PROTO_RI_COUNT)
249*0Sstevel@tonic-gate 			goto unsupported;
250*0Sstevel@tonic-gate 
251*0Sstevel@tonic-gate 		/*
252*0Sstevel@tonic-gate 		 * Grab the jump table entry.
253*0Sstevel@tonic-gate 		 */
254*0Sstevel@tonic-gate 		prip = &proto_ri[prim];
255*0Sstevel@tonic-gate 	}
256*0Sstevel@tonic-gate 
257*0Sstevel@tonic-gate 	ASSERT(prip->pri_prim == prim);
258*0Sstevel@tonic-gate 
259*0Sstevel@tonic-gate 	/*
260*0Sstevel@tonic-gate 	 * If this primitive causes the data-link channel used by this
261*0Sstevel@tonic-gate 	 * object to become active, then we need to notify dls.  Note that
262*0Sstevel@tonic-gate 	 * if we're already passive by having succesfully processed a
263*0Sstevel@tonic-gate 	 * DL_PASSIVE_REQ, then active primitives do not cause us to become
264*0Sstevel@tonic-gate 	 * active.
265*0Sstevel@tonic-gate 	 */
266*0Sstevel@tonic-gate 	if (prip->pri_active && dsp->ds_passivestate == DLD_UNINITIALIZED) {
267*0Sstevel@tonic-gate 		if (!dls_active_set(dsp->ds_dc)) {
268*0Sstevel@tonic-gate 			dlerrorack(dsp->ds_wq, mp, prim, DL_SYSERR, EBUSY);
269*0Sstevel@tonic-gate 			return;
270*0Sstevel@tonic-gate 		}
271*0Sstevel@tonic-gate 	}
272*0Sstevel@tonic-gate 
273*0Sstevel@tonic-gate 	/*
274*0Sstevel@tonic-gate 	 * Check whether we need, and whether we have, exclusive access to
275*0Sstevel@tonic-gate 	 * the stream.
276*0Sstevel@tonic-gate 	 */
277*0Sstevel@tonic-gate 	if (prip->pri_needexcl) {
278*0Sstevel@tonic-gate 		/*
279*0Sstevel@tonic-gate 		 * We only have shared access and we need exclusive access.
280*0Sstevel@tonic-gate 		 */
281*0Sstevel@tonic-gate 		ASSERT(!PERIM_EXCL(dsp->ds_wq));
282*0Sstevel@tonic-gate 
283*0Sstevel@tonic-gate 		/*
284*0Sstevel@tonic-gate 		 * Process via qwriter(9f).
285*0Sstevel@tonic-gate 		 */
286*0Sstevel@tonic-gate 		qwriter(dsp->ds_wq, mp, proto_excl, PERIM_INNER);
287*0Sstevel@tonic-gate 		return;
288*0Sstevel@tonic-gate 	}
289*0Sstevel@tonic-gate 
290*0Sstevel@tonic-gate 	success = prip->pri_fn(dsp, udlp, mp);
291*0Sstevel@tonic-gate 	if (prip->pri_active && dsp->ds_passivestate == DLD_UNINITIALIZED) {
292*0Sstevel@tonic-gate 		if (success)
293*0Sstevel@tonic-gate 			dsp->ds_passivestate = DLD_ACTIVE;
294*0Sstevel@tonic-gate 		else
295*0Sstevel@tonic-gate 			dls_active_clear(dsp->ds_dc);
296*0Sstevel@tonic-gate 	}
297*0Sstevel@tonic-gate 
298*0Sstevel@tonic-gate 	return;
299*0Sstevel@tonic-gate 
300*0Sstevel@tonic-gate unsupported:
301*0Sstevel@tonic-gate 	(void) proto_req(dsp, udlp, mp);
302*0Sstevel@tonic-gate }
303*0Sstevel@tonic-gate 
304*0Sstevel@tonic-gate /*
305*0Sstevel@tonic-gate  * Called via qwriter(9f).
306*0Sstevel@tonic-gate  */
307*0Sstevel@tonic-gate static void
308*0Sstevel@tonic-gate proto_excl(queue_t *q, mblk_t *mp)
309*0Sstevel@tonic-gate {
310*0Sstevel@tonic-gate 	dld_str_t		*dsp = q->q_ptr;
311*0Sstevel@tonic-gate 	union DL_primitives	*udlp;
312*0Sstevel@tonic-gate 	t_uscalar_t		prim;
313*0Sstevel@tonic-gate 	proto_req_info_t	*prip;
314*0Sstevel@tonic-gate 	boolean_t		success;
315*0Sstevel@tonic-gate 
316*0Sstevel@tonic-gate 	ASSERT(MBLKL(mp) >= sizeof (t_uscalar_t));
317*0Sstevel@tonic-gate 
318*0Sstevel@tonic-gate 	udlp = (union DL_primitives *)mp->b_rptr;
319*0Sstevel@tonic-gate 	prim = udlp->dl_primitive;
320*0Sstevel@tonic-gate 
321*0Sstevel@tonic-gate 	/*
322*0Sstevel@tonic-gate 	 * Select the correct jump table.
323*0Sstevel@tonic-gate 	 */
324*0Sstevel@tonic-gate 	if (prim & DL_SOLARIS) {
325*0Sstevel@tonic-gate 		/*
326*0Sstevel@tonic-gate 		 * Entries in the 'solaris extensions' jump table
327*0Sstevel@tonic-gate 		 * have an extra bit in the primitive value. Clear it
328*0Sstevel@tonic-gate 		 * to do the lookup.
329*0Sstevel@tonic-gate 		 */
330*0Sstevel@tonic-gate 		prim &= ~DL_SOLARIS;
331*0Sstevel@tonic-gate 
332*0Sstevel@tonic-gate 		/*
333*0Sstevel@tonic-gate 		 * Grab the jump table entry.
334*0Sstevel@tonic-gate 		 */
335*0Sstevel@tonic-gate 		ASSERT(prim < PROTO_SRI_COUNT);
336*0Sstevel@tonic-gate 		prip = &proto_sri[prim];
337*0Sstevel@tonic-gate 
338*0Sstevel@tonic-gate 		/*
339*0Sstevel@tonic-gate 		 * OR the cleared bit back in to make the primitive valid
340*0Sstevel@tonic-gate 		 * again.
341*0Sstevel@tonic-gate 		 */
342*0Sstevel@tonic-gate 		prim |= DL_SOLARIS;
343*0Sstevel@tonic-gate 	} else {
344*0Sstevel@tonic-gate 		/*
345*0Sstevel@tonic-gate 		 * Grab the jump table entry.
346*0Sstevel@tonic-gate 		 */
347*0Sstevel@tonic-gate 		ASSERT(prim < PROTO_RI_COUNT);
348*0Sstevel@tonic-gate 		prip = &proto_ri[prim];
349*0Sstevel@tonic-gate 	}
350*0Sstevel@tonic-gate 
351*0Sstevel@tonic-gate 	ASSERT(prip->pri_prim == prim);
352*0Sstevel@tonic-gate 
353*0Sstevel@tonic-gate 	success = prip->pri_fn(dsp, udlp, mp);
354*0Sstevel@tonic-gate 	if (prip->pri_active && dsp->ds_passivestate == DLD_UNINITIALIZED) {
355*0Sstevel@tonic-gate 		if (success)
356*0Sstevel@tonic-gate 			dsp->ds_passivestate = DLD_ACTIVE;
357*0Sstevel@tonic-gate 		else
358*0Sstevel@tonic-gate 			dls_active_clear(dsp->ds_dc);
359*0Sstevel@tonic-gate 	}
360*0Sstevel@tonic-gate }
361*0Sstevel@tonic-gate 
362*0Sstevel@tonic-gate /*
363*0Sstevel@tonic-gate  * DL_INFO_REQ
364*0Sstevel@tonic-gate  */
365*0Sstevel@tonic-gate /*ARGSUSED*/
366*0Sstevel@tonic-gate static boolean_t
367*0Sstevel@tonic-gate proto_info_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp)
368*0Sstevel@tonic-gate {
369*0Sstevel@tonic-gate 	proto_info_ack(dsp, mp);
370*0Sstevel@tonic-gate 	return (B_TRUE);
371*0Sstevel@tonic-gate }
372*0Sstevel@tonic-gate 
373*0Sstevel@tonic-gate /*
374*0Sstevel@tonic-gate  * DL_ATTACH_REQ
375*0Sstevel@tonic-gate  */
376*0Sstevel@tonic-gate static boolean_t
377*0Sstevel@tonic-gate proto_attach_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp)
378*0Sstevel@tonic-gate {
379*0Sstevel@tonic-gate 	dl_attach_req_t		*dlp = (dl_attach_req_t *)udlp;
380*0Sstevel@tonic-gate 	t_scalar_t		index;
381*0Sstevel@tonic-gate 	dld_node_t		*dnp;
382*0Sstevel@tonic-gate 	dld_ppa_t		*dpp;
383*0Sstevel@tonic-gate 	int			err;
384*0Sstevel@tonic-gate 
385*0Sstevel@tonic-gate 	ASSERT(PERIM_EXCL(dsp->ds_wq));
386*0Sstevel@tonic-gate 
387*0Sstevel@tonic-gate 	if (dsp->ds_dlstate != DL_UNATTACHED) {
388*0Sstevel@tonic-gate 		dlerrorack(dsp->ds_wq, mp, DL_ATTACH_REQ, DL_OUTSTATE, 0);
389*0Sstevel@tonic-gate 		return (B_FALSE);
390*0Sstevel@tonic-gate 	}
391*0Sstevel@tonic-gate 
392*0Sstevel@tonic-gate 	if (MBLKL(mp) < sizeof (dl_attach_req_t)) {
393*0Sstevel@tonic-gate 		dlerrorack(dsp->ds_wq, mp, DL_ATTACH_REQ, DL_BADPRIM, 0);
394*0Sstevel@tonic-gate 		return (B_FALSE);
395*0Sstevel@tonic-gate 	}
396*0Sstevel@tonic-gate 
397*0Sstevel@tonic-gate 	index = dlp->dl_ppa;
398*0Sstevel@tonic-gate 
399*0Sstevel@tonic-gate 	dnp = dsp->ds_dnp;
400*0Sstevel@tonic-gate 	ASSERT(dnp->dn_style == DL_STYLE2);
401*0Sstevel@tonic-gate 
402*0Sstevel@tonic-gate 	if ((dpp = dld_node_ppa_find(dnp, index)) == NULL) {
403*0Sstevel@tonic-gate 		dlerrorack(dsp->ds_wq, mp, DL_ATTACH_REQ, DL_BADPPA, 0);
404*0Sstevel@tonic-gate 		return (B_FALSE);
405*0Sstevel@tonic-gate 	}
406*0Sstevel@tonic-gate 
407*0Sstevel@tonic-gate 	dsp->ds_dlstate = DL_ATTACH_PENDING;
408*0Sstevel@tonic-gate 
409*0Sstevel@tonic-gate 	err = dld_str_attach(dsp, dpp);
410*0Sstevel@tonic-gate 	proto_attach_ack(dsp, mp, err);
411*0Sstevel@tonic-gate 	return (err == 0);
412*0Sstevel@tonic-gate }
413*0Sstevel@tonic-gate 
414*0Sstevel@tonic-gate /*
415*0Sstevel@tonic-gate  * DL_DETACH_REQ
416*0Sstevel@tonic-gate  */
417*0Sstevel@tonic-gate /*ARGSUSED*/
418*0Sstevel@tonic-gate static boolean_t
419*0Sstevel@tonic-gate proto_detach_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp)
420*0Sstevel@tonic-gate {
421*0Sstevel@tonic-gate 	ASSERT(PERIM_EXCL(dsp->ds_wq));
422*0Sstevel@tonic-gate 
423*0Sstevel@tonic-gate 	if (dsp->ds_dlstate != DL_UNBOUND) {
424*0Sstevel@tonic-gate 		dlerrorack(dsp->ds_wq, mp, DL_DETACH_REQ, DL_OUTSTATE, 0);
425*0Sstevel@tonic-gate 		return (B_FALSE);
426*0Sstevel@tonic-gate 	}
427*0Sstevel@tonic-gate 
428*0Sstevel@tonic-gate 	if (MBLKL(mp) < sizeof (dl_detach_req_t)) {
429*0Sstevel@tonic-gate 		dlerrorack(dsp->ds_wq, mp, DL_DETACH_REQ, DL_BADPRIM, 0);
430*0Sstevel@tonic-gate 		return (B_FALSE);
431*0Sstevel@tonic-gate 	}
432*0Sstevel@tonic-gate 
433*0Sstevel@tonic-gate 	if ((dsp->ds_dnp)->dn_style == DL_STYLE1) {
434*0Sstevel@tonic-gate 		dlerrorack(dsp->ds_wq, mp, DL_DETACH_REQ, DL_BADPRIM, 0);
435*0Sstevel@tonic-gate 		return (B_FALSE);
436*0Sstevel@tonic-gate 	}
437*0Sstevel@tonic-gate 
438*0Sstevel@tonic-gate 	dsp->ds_dlstate = DL_DETACH_PENDING;
439*0Sstevel@tonic-gate 
440*0Sstevel@tonic-gate 	dld_str_detach(dsp);
441*0Sstevel@tonic-gate 	proto_detach_ack(dsp, mp);
442*0Sstevel@tonic-gate 	return (B_TRUE);
443*0Sstevel@tonic-gate }
444*0Sstevel@tonic-gate 
445*0Sstevel@tonic-gate /*
446*0Sstevel@tonic-gate  * DL_BIND_REQ
447*0Sstevel@tonic-gate  */
448*0Sstevel@tonic-gate static boolean_t
449*0Sstevel@tonic-gate proto_bind_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp)
450*0Sstevel@tonic-gate {
451*0Sstevel@tonic-gate 	dl_bind_req_t		*dlp = (dl_bind_req_t *)udlp;
452*0Sstevel@tonic-gate 	int			err;
453*0Sstevel@tonic-gate 
454*0Sstevel@tonic-gate 	ASSERT(PERIM_EXCL(dsp->ds_wq));
455*0Sstevel@tonic-gate 
456*0Sstevel@tonic-gate 	if (dsp->ds_dlstate != DL_UNBOUND) {
457*0Sstevel@tonic-gate 		dlerrorack(dsp->ds_wq, mp, DL_BIND_REQ, DL_OUTSTATE, 0);
458*0Sstevel@tonic-gate 		return (B_FALSE);
459*0Sstevel@tonic-gate 	}
460*0Sstevel@tonic-gate 
461*0Sstevel@tonic-gate 	if (MBLKL(mp) < sizeof (dl_bind_req_t)) {
462*0Sstevel@tonic-gate 		dlerrorack(dsp->ds_wq, mp, DL_BIND_REQ, DL_BADPRIM, 0);
463*0Sstevel@tonic-gate 		return (B_FALSE);
464*0Sstevel@tonic-gate 	}
465*0Sstevel@tonic-gate 
466*0Sstevel@tonic-gate 	if (dlp->dl_xidtest_flg != 0) {
467*0Sstevel@tonic-gate 		dlerrorack(dsp->ds_wq, mp, DL_BIND_REQ, DL_NOAUTO, 0);
468*0Sstevel@tonic-gate 		return (B_FALSE);
469*0Sstevel@tonic-gate 	}
470*0Sstevel@tonic-gate 
471*0Sstevel@tonic-gate 	if (dlp->dl_service_mode != DL_CLDLS) {
472*0Sstevel@tonic-gate 		dlerrorack(dsp->ds_wq, mp, DL_BIND_REQ, DL_UNSUPPORTED, 0);
473*0Sstevel@tonic-gate 		return (B_FALSE);
474*0Sstevel@tonic-gate 	}
475*0Sstevel@tonic-gate 
476*0Sstevel@tonic-gate 	dsp->ds_dlstate = DL_BIND_PENDING;
477*0Sstevel@tonic-gate 
478*0Sstevel@tonic-gate 	/*
479*0Sstevel@tonic-gate 	 * Set the receive callback.
480*0Sstevel@tonic-gate 	 */
481*0Sstevel@tonic-gate 	dls_rx_set(dsp->ds_dc, dld_str_rx_unitdata, (void *)dsp);
482*0Sstevel@tonic-gate 
483*0Sstevel@tonic-gate 	/*
484*0Sstevel@tonic-gate 	 * Bind the channel such that it can receive packets.
485*0Sstevel@tonic-gate 	 */
486*0Sstevel@tonic-gate 	dsp->ds_sap = dlp->dl_sap;
487*0Sstevel@tonic-gate 	err = dls_bind(dsp->ds_dc, dlp->dl_sap);
488*0Sstevel@tonic-gate 
489*0Sstevel@tonic-gate 	proto_bind_ack(dsp, mp, err);
490*0Sstevel@tonic-gate 	return (err == 0);
491*0Sstevel@tonic-gate }
492*0Sstevel@tonic-gate 
493*0Sstevel@tonic-gate /*
494*0Sstevel@tonic-gate  * DL_UNBIND_REQ
495*0Sstevel@tonic-gate  */
496*0Sstevel@tonic-gate /*ARGSUSED*/
497*0Sstevel@tonic-gate static boolean_t
498*0Sstevel@tonic-gate proto_unbind_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp)
499*0Sstevel@tonic-gate {
500*0Sstevel@tonic-gate 	ASSERT(PERIM_EXCL(dsp->ds_wq));
501*0Sstevel@tonic-gate 
502*0Sstevel@tonic-gate 	if (dsp->ds_dlstate != DL_IDLE) {
503*0Sstevel@tonic-gate 		dlerrorack(dsp->ds_wq, mp, DL_UNBIND_REQ, DL_OUTSTATE, 0);
504*0Sstevel@tonic-gate 		return (B_FALSE);
505*0Sstevel@tonic-gate 	}
506*0Sstevel@tonic-gate 
507*0Sstevel@tonic-gate 	if (MBLKL(mp) < sizeof (dl_unbind_req_t)) {
508*0Sstevel@tonic-gate 		dlerrorack(dsp->ds_wq, mp, DL_BIND_REQ, DL_BADPRIM, 0);
509*0Sstevel@tonic-gate 		return (B_FALSE);
510*0Sstevel@tonic-gate 	}
511*0Sstevel@tonic-gate 
512*0Sstevel@tonic-gate 	dsp->ds_dlstate = DL_UNBIND_PENDING;
513*0Sstevel@tonic-gate 
514*0Sstevel@tonic-gate 	/*
515*0Sstevel@tonic-gate 	 * Flush any remaining packets scheduled for transmission.
516*0Sstevel@tonic-gate 	 */
517*0Sstevel@tonic-gate 	flushq(dsp->ds_wq, FLUSHALL);
518*0Sstevel@tonic-gate 
519*0Sstevel@tonic-gate 	/*
520*0Sstevel@tonic-gate 	 * Reset the M_DATA handler.
521*0Sstevel@tonic-gate 	 */
522*0Sstevel@tonic-gate 	dld_str_tx_drop(dsp);
523*0Sstevel@tonic-gate 
524*0Sstevel@tonic-gate 	/*
525*0Sstevel@tonic-gate 	 * Unbind the channel to stop packets being received.
526*0Sstevel@tonic-gate 	 */
527*0Sstevel@tonic-gate 	dls_unbind(dsp->ds_dc);
528*0Sstevel@tonic-gate 
529*0Sstevel@tonic-gate 	/*
530*0Sstevel@tonic-gate 	 * Disable polling mode, if it is enabled.
531*0Sstevel@tonic-gate 	 */
532*0Sstevel@tonic-gate 	proto_poll_disable(dsp);
533*0Sstevel@tonic-gate 
534*0Sstevel@tonic-gate 	/*
535*0Sstevel@tonic-gate 	 * Clear the receive callback.
536*0Sstevel@tonic-gate 	 */
537*0Sstevel@tonic-gate 	dls_rx_set(dsp->ds_dc, NULL, NULL);
538*0Sstevel@tonic-gate 
539*0Sstevel@tonic-gate 	/*
540*0Sstevel@tonic-gate 	 * Set the mode back to the default (unitdata).
541*0Sstevel@tonic-gate 	 */
542*0Sstevel@tonic-gate 	dsp->ds_mode = DLD_UNITDATA;
543*0Sstevel@tonic-gate 
544*0Sstevel@tonic-gate 	proto_unbind_ack(dsp, mp);
545*0Sstevel@tonic-gate 	return (B_TRUE);
546*0Sstevel@tonic-gate }
547*0Sstevel@tonic-gate 
548*0Sstevel@tonic-gate /*
549*0Sstevel@tonic-gate  * DL_PROMISCON_REQ
550*0Sstevel@tonic-gate  */
551*0Sstevel@tonic-gate static boolean_t
552*0Sstevel@tonic-gate proto_promiscon_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp)
553*0Sstevel@tonic-gate {
554*0Sstevel@tonic-gate 	dl_promiscon_req_t	*dlp = (dl_promiscon_req_t *)udlp;
555*0Sstevel@tonic-gate 	int			err;
556*0Sstevel@tonic-gate 
557*0Sstevel@tonic-gate 	ASSERT(PERIM_EXCL(dsp->ds_wq));
558*0Sstevel@tonic-gate 
559*0Sstevel@tonic-gate 	if (dsp->ds_dlstate == DL_UNATTACHED ||
560*0Sstevel@tonic-gate 	    DL_ACK_PENDING(dsp->ds_dlstate)) {
561*0Sstevel@tonic-gate 		dlerrorack(dsp->ds_wq, mp, DL_PROMISCON_REQ, DL_OUTSTATE, 0);
562*0Sstevel@tonic-gate 		return (B_FALSE);
563*0Sstevel@tonic-gate 	}
564*0Sstevel@tonic-gate 
565*0Sstevel@tonic-gate 	if (MBLKL(mp) < sizeof (dl_promiscon_req_t)) {
566*0Sstevel@tonic-gate 		dlerrorack(dsp->ds_wq, mp, DL_PROMISCON_REQ, DL_BADPRIM, 0);
567*0Sstevel@tonic-gate 		return (B_FALSE);
568*0Sstevel@tonic-gate 	}
569*0Sstevel@tonic-gate 
570*0Sstevel@tonic-gate 	switch (dlp->dl_level) {
571*0Sstevel@tonic-gate 	case DL_PROMISC_SAP:
572*0Sstevel@tonic-gate 		dsp->ds_promisc |= DLS_PROMISC_SAP;
573*0Sstevel@tonic-gate 		break;
574*0Sstevel@tonic-gate 
575*0Sstevel@tonic-gate 	case DL_PROMISC_MULTI:
576*0Sstevel@tonic-gate 		dsp->ds_promisc |= DLS_PROMISC_MULTI;
577*0Sstevel@tonic-gate 		break;
578*0Sstevel@tonic-gate 
579*0Sstevel@tonic-gate 	case DL_PROMISC_PHYS:
580*0Sstevel@tonic-gate 		dsp->ds_promisc |= DLS_PROMISC_PHYS;
581*0Sstevel@tonic-gate 		break;
582*0Sstevel@tonic-gate 
583*0Sstevel@tonic-gate 	default:
584*0Sstevel@tonic-gate 		dlerrorack(dsp->ds_wq, mp, DL_PROMISCON_REQ, DL_NOTSUPPORTED,
585*0Sstevel@tonic-gate 		    0);
586*0Sstevel@tonic-gate 		return (B_FALSE);
587*0Sstevel@tonic-gate 	}
588*0Sstevel@tonic-gate 
589*0Sstevel@tonic-gate 	/*
590*0Sstevel@tonic-gate 	 * Adjust channel promiscuity.
591*0Sstevel@tonic-gate 	 */
592*0Sstevel@tonic-gate 	err = dls_promisc(dsp->ds_dc, dsp->ds_promisc);
593*0Sstevel@tonic-gate 	proto_promiscon_ack(dsp, mp, err);
594*0Sstevel@tonic-gate 	return (err == 0);
595*0Sstevel@tonic-gate }
596*0Sstevel@tonic-gate 
597*0Sstevel@tonic-gate /*
598*0Sstevel@tonic-gate  * DL_PROMISCOFF_REQ
599*0Sstevel@tonic-gate  */
600*0Sstevel@tonic-gate static boolean_t
601*0Sstevel@tonic-gate proto_promiscoff_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp)
602*0Sstevel@tonic-gate {
603*0Sstevel@tonic-gate 	dl_promiscoff_req_t	*dlp = (dl_promiscoff_req_t *)udlp;
604*0Sstevel@tonic-gate 	int			err;
605*0Sstevel@tonic-gate 
606*0Sstevel@tonic-gate 	ASSERT(PERIM_EXCL(dsp->ds_wq));
607*0Sstevel@tonic-gate 
608*0Sstevel@tonic-gate 	if (dsp->ds_dlstate == DL_UNATTACHED ||
609*0Sstevel@tonic-gate 	    DL_ACK_PENDING(dsp->ds_dlstate)) {
610*0Sstevel@tonic-gate 		dlerrorack(dsp->ds_wq, mp, DL_PROMISCOFF_REQ, DL_OUTSTATE, 0);
611*0Sstevel@tonic-gate 		return (B_FALSE);
612*0Sstevel@tonic-gate 	}
613*0Sstevel@tonic-gate 
614*0Sstevel@tonic-gate 	if (MBLKL(mp) < sizeof (dl_promiscoff_req_t)) {
615*0Sstevel@tonic-gate 		dlerrorack(dsp->ds_wq, mp, DL_PROMISCOFF_REQ, DL_BADPRIM, 0);
616*0Sstevel@tonic-gate 		return (B_FALSE);
617*0Sstevel@tonic-gate 	}
618*0Sstevel@tonic-gate 
619*0Sstevel@tonic-gate 	switch (dlp->dl_level) {
620*0Sstevel@tonic-gate 	case DL_PROMISC_SAP:
621*0Sstevel@tonic-gate 		if (!(dsp->ds_promisc & DLS_PROMISC_SAP))
622*0Sstevel@tonic-gate 			goto notenab;
623*0Sstevel@tonic-gate 
624*0Sstevel@tonic-gate 		dsp->ds_promisc &= ~DLS_PROMISC_SAP;
625*0Sstevel@tonic-gate 		break;
626*0Sstevel@tonic-gate 
627*0Sstevel@tonic-gate 	case DL_PROMISC_MULTI:
628*0Sstevel@tonic-gate 		if (!(dsp->ds_promisc & DLS_PROMISC_MULTI))
629*0Sstevel@tonic-gate 			goto notenab;
630*0Sstevel@tonic-gate 
631*0Sstevel@tonic-gate 		dsp->ds_promisc &= ~DLS_PROMISC_MULTI;
632*0Sstevel@tonic-gate 		break;
633*0Sstevel@tonic-gate 
634*0Sstevel@tonic-gate 	case DL_PROMISC_PHYS:
635*0Sstevel@tonic-gate 		if (!(dsp->ds_promisc & DLS_PROMISC_PHYS))
636*0Sstevel@tonic-gate 			goto notenab;
637*0Sstevel@tonic-gate 
638*0Sstevel@tonic-gate 		dsp->ds_promisc &= ~DLS_PROMISC_PHYS;
639*0Sstevel@tonic-gate 		break;
640*0Sstevel@tonic-gate 
641*0Sstevel@tonic-gate 	default:
642*0Sstevel@tonic-gate 		dlerrorack(dsp->ds_wq, mp, DL_PROMISCOFF_REQ, DL_NOTSUPPORTED,
643*0Sstevel@tonic-gate 		    0);
644*0Sstevel@tonic-gate 		return (B_FALSE);
645*0Sstevel@tonic-gate 	}
646*0Sstevel@tonic-gate 
647*0Sstevel@tonic-gate 	/*
648*0Sstevel@tonic-gate 	 * Adjust channel promiscuity.
649*0Sstevel@tonic-gate 	 */
650*0Sstevel@tonic-gate 	err = dls_promisc(dsp->ds_dc, dsp->ds_promisc);
651*0Sstevel@tonic-gate 
652*0Sstevel@tonic-gate 	proto_promiscoff_ack(dsp, mp, err);
653*0Sstevel@tonic-gate 	return (err == 0);
654*0Sstevel@tonic-gate 
655*0Sstevel@tonic-gate notenab:
656*0Sstevel@tonic-gate 	dlerrorack(dsp->ds_wq, mp, DL_PROMISCOFF_REQ, DL_NOTENAB, 0);
657*0Sstevel@tonic-gate 	return (B_FALSE);
658*0Sstevel@tonic-gate }
659*0Sstevel@tonic-gate 
660*0Sstevel@tonic-gate /*
661*0Sstevel@tonic-gate  * DL_ENABMULTI_REQ
662*0Sstevel@tonic-gate  */
663*0Sstevel@tonic-gate static boolean_t
664*0Sstevel@tonic-gate proto_enabmulti_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp)
665*0Sstevel@tonic-gate {
666*0Sstevel@tonic-gate 	dl_enabmulti_req_t	*dlp = (dl_enabmulti_req_t *)udlp;
667*0Sstevel@tonic-gate 	int			err;
668*0Sstevel@tonic-gate 
669*0Sstevel@tonic-gate 	ASSERT(PERIM_EXCL(dsp->ds_wq));
670*0Sstevel@tonic-gate 
671*0Sstevel@tonic-gate 	if (dsp->ds_dlstate == DL_UNATTACHED ||
672*0Sstevel@tonic-gate 	    DL_ACK_PENDING(dsp->ds_dlstate)) {
673*0Sstevel@tonic-gate 		dlerrorack(dsp->ds_wq, mp, DL_ENABMULTI_REQ, DL_OUTSTATE, 0);
674*0Sstevel@tonic-gate 		return (B_FALSE);
675*0Sstevel@tonic-gate 	}
676*0Sstevel@tonic-gate 
677*0Sstevel@tonic-gate 	if (MBLKL(mp) < sizeof (dl_enabmulti_req_t) ||
678*0Sstevel@tonic-gate 	    !MBLKIN(mp, dlp->dl_addr_offset, dlp->dl_addr_length) ||
679*0Sstevel@tonic-gate 	    dlp->dl_addr_length != dsp->ds_mip->mi_addr_length) {
680*0Sstevel@tonic-gate 		dlerrorack(dsp->ds_wq, mp, DL_ENABMULTI_REQ, DL_BADPRIM, 0);
681*0Sstevel@tonic-gate 		return (B_FALSE);
682*0Sstevel@tonic-gate 	}
683*0Sstevel@tonic-gate 
684*0Sstevel@tonic-gate 	err = dls_multicst_add(dsp->ds_dc, mp->b_rptr + dlp->dl_addr_offset);
685*0Sstevel@tonic-gate 	proto_enabmulti_ack(dsp, mp, err);
686*0Sstevel@tonic-gate 	return (err == 0);
687*0Sstevel@tonic-gate }
688*0Sstevel@tonic-gate 
689*0Sstevel@tonic-gate /*
690*0Sstevel@tonic-gate  * DL_DISABMULTI_REQ
691*0Sstevel@tonic-gate  */
692*0Sstevel@tonic-gate static boolean_t
693*0Sstevel@tonic-gate proto_disabmulti_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp)
694*0Sstevel@tonic-gate {
695*0Sstevel@tonic-gate 	dl_disabmulti_req_t	*dlp = (dl_disabmulti_req_t *)udlp;
696*0Sstevel@tonic-gate 	int			err;
697*0Sstevel@tonic-gate 
698*0Sstevel@tonic-gate 	ASSERT(PERIM_EXCL(dsp->ds_wq));
699*0Sstevel@tonic-gate 
700*0Sstevel@tonic-gate 	if (dsp->ds_dlstate == DL_UNATTACHED ||
701*0Sstevel@tonic-gate 	    DL_ACK_PENDING(dsp->ds_dlstate)) {
702*0Sstevel@tonic-gate 		dlerrorack(dsp->ds_wq, mp, DL_DISABMULTI_REQ, DL_OUTSTATE, 0);
703*0Sstevel@tonic-gate 		return (B_FALSE);
704*0Sstevel@tonic-gate 	}
705*0Sstevel@tonic-gate 
706*0Sstevel@tonic-gate 	if (MBLKL(mp) < sizeof (dl_disabmulti_req_t) ||
707*0Sstevel@tonic-gate 	    !MBLKIN(mp, dlp->dl_addr_offset, dlp->dl_addr_length) ||
708*0Sstevel@tonic-gate 	    dlp->dl_addr_length != dsp->ds_mip->mi_addr_length) {
709*0Sstevel@tonic-gate 		dlerrorack(dsp->ds_wq, mp, DL_DISABMULTI_REQ, DL_BADPRIM, 0);
710*0Sstevel@tonic-gate 		return (B_FALSE);
711*0Sstevel@tonic-gate 	}
712*0Sstevel@tonic-gate 
713*0Sstevel@tonic-gate 	err = dls_multicst_remove(dsp->ds_dc, mp->b_rptr + dlp->dl_addr_offset);
714*0Sstevel@tonic-gate 	proto_disabmulti_ack(dsp, mp, err);
715*0Sstevel@tonic-gate 	return (err == 0);
716*0Sstevel@tonic-gate }
717*0Sstevel@tonic-gate 
718*0Sstevel@tonic-gate /*
719*0Sstevel@tonic-gate  * DL_PHYS_ADDR_REQ
720*0Sstevel@tonic-gate  */
721*0Sstevel@tonic-gate static boolean_t
722*0Sstevel@tonic-gate proto_physaddr_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp)
723*0Sstevel@tonic-gate {
724*0Sstevel@tonic-gate 	dl_phys_addr_req_t	*dlp = (dl_phys_addr_req_t *)udlp;
725*0Sstevel@tonic-gate 
726*0Sstevel@tonic-gate 	if (dsp->ds_dlstate == DL_UNATTACHED ||
727*0Sstevel@tonic-gate 	    DL_ACK_PENDING(dsp->ds_dlstate)) {
728*0Sstevel@tonic-gate 		dlerrorack(dsp->ds_wq, mp, DL_PHYS_ADDR_REQ, DL_OUTSTATE, 0);
729*0Sstevel@tonic-gate 		return (B_FALSE);
730*0Sstevel@tonic-gate 	}
731*0Sstevel@tonic-gate 
732*0Sstevel@tonic-gate 	if (MBLKL(mp) < sizeof (dl_phys_addr_req_t)) {
733*0Sstevel@tonic-gate 		dlerrorack(dsp->ds_wq, mp, DL_PHYS_ADDR_REQ, DL_BADPRIM, 0);
734*0Sstevel@tonic-gate 		return (B_FALSE);
735*0Sstevel@tonic-gate 	}
736*0Sstevel@tonic-gate 
737*0Sstevel@tonic-gate 	if (dlp->dl_addr_type != DL_CURR_PHYS_ADDR &&
738*0Sstevel@tonic-gate 	    dlp->dl_addr_type != DL_FACT_PHYS_ADDR) {
739*0Sstevel@tonic-gate 		dlerrorack(dsp->ds_wq, mp, DL_PHYS_ADDR_REQ, DL_UNSUPPORTED, 0);
740*0Sstevel@tonic-gate 		return (B_FALSE);
741*0Sstevel@tonic-gate 	}
742*0Sstevel@tonic-gate 
743*0Sstevel@tonic-gate 	proto_physaddr_ack(dsp, mp, dlp->dl_addr_type);
744*0Sstevel@tonic-gate 	return (B_TRUE);
745*0Sstevel@tonic-gate }
746*0Sstevel@tonic-gate 
747*0Sstevel@tonic-gate /*
748*0Sstevel@tonic-gate  * DL_SET_PHYS_ADDR_REQ
749*0Sstevel@tonic-gate  */
750*0Sstevel@tonic-gate static boolean_t
751*0Sstevel@tonic-gate proto_setphysaddr_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp)
752*0Sstevel@tonic-gate {
753*0Sstevel@tonic-gate 	dl_set_phys_addr_req_t	*dlp = (dl_set_phys_addr_req_t *)udlp;
754*0Sstevel@tonic-gate 	int			err;
755*0Sstevel@tonic-gate 
756*0Sstevel@tonic-gate 	ASSERT(PERIM_EXCL(dsp->ds_wq));
757*0Sstevel@tonic-gate 
758*0Sstevel@tonic-gate 	if (dsp->ds_dlstate == DL_UNATTACHED ||
759*0Sstevel@tonic-gate 	    DL_ACK_PENDING(dsp->ds_dlstate)) {
760*0Sstevel@tonic-gate 		dlerrorack(dsp->ds_wq, mp, DL_SET_PHYS_ADDR_REQ, DL_OUTSTATE,
761*0Sstevel@tonic-gate 		    0);
762*0Sstevel@tonic-gate 		return (B_FALSE);
763*0Sstevel@tonic-gate 	}
764*0Sstevel@tonic-gate 
765*0Sstevel@tonic-gate 	if (MBLKL(mp) < sizeof (dl_set_phys_addr_req_t) ||
766*0Sstevel@tonic-gate 	    !MBLKIN(mp, dlp->dl_addr_offset, dlp->dl_addr_length) ||
767*0Sstevel@tonic-gate 	    dlp->dl_addr_length != dsp->ds_mip->mi_addr_length) {
768*0Sstevel@tonic-gate 		dlerrorack(dsp->ds_wq, mp, DL_SET_PHYS_ADDR_REQ, DL_BADPRIM,
769*0Sstevel@tonic-gate 		    0);
770*0Sstevel@tonic-gate 		return (B_FALSE);
771*0Sstevel@tonic-gate 	}
772*0Sstevel@tonic-gate 
773*0Sstevel@tonic-gate 	err = mac_unicst_set(dsp->ds_mh, mp->b_rptr + dlp->dl_addr_offset);
774*0Sstevel@tonic-gate 	proto_setphysaddr_ack(dsp, mp, err);
775*0Sstevel@tonic-gate 	return (err == 0);
776*0Sstevel@tonic-gate }
777*0Sstevel@tonic-gate 
778*0Sstevel@tonic-gate /*
779*0Sstevel@tonic-gate  * DL_UDQOS_REQ
780*0Sstevel@tonic-gate  */
781*0Sstevel@tonic-gate static boolean_t
782*0Sstevel@tonic-gate proto_udqos_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp)
783*0Sstevel@tonic-gate {
784*0Sstevel@tonic-gate 	dl_udqos_req_t		*dlp = (dl_udqos_req_t *)udlp;
785*0Sstevel@tonic-gate 	dl_qos_cl_sel1_t	*selp;
786*0Sstevel@tonic-gate 	int			off, len;
787*0Sstevel@tonic-gate 
788*0Sstevel@tonic-gate 	ASSERT(PERIM_EXCL(dsp->ds_wq));
789*0Sstevel@tonic-gate 
790*0Sstevel@tonic-gate 	off = dlp->dl_qos_offset;
791*0Sstevel@tonic-gate 	len = dlp->dl_qos_length;
792*0Sstevel@tonic-gate 
793*0Sstevel@tonic-gate 	if (MBLKL(mp) < sizeof (dl_udqos_req_t) || !MBLKIN(mp, off, len)) {
794*0Sstevel@tonic-gate 		dlerrorack(dsp->ds_wq, mp, DL_UDQOS_REQ, DL_BADPRIM, 0);
795*0Sstevel@tonic-gate 		return (B_FALSE);
796*0Sstevel@tonic-gate 	}
797*0Sstevel@tonic-gate 
798*0Sstevel@tonic-gate 	selp = (dl_qos_cl_sel1_t *)(mp->b_rptr + off);
799*0Sstevel@tonic-gate 	if (selp->dl_qos_type != DL_QOS_CL_SEL1) {
800*0Sstevel@tonic-gate 		dlerrorack(dsp->ds_wq, mp, DL_UDQOS_REQ, DL_BADQOSTYPE, 0);
801*0Sstevel@tonic-gate 		return (B_FALSE);
802*0Sstevel@tonic-gate 	}
803*0Sstevel@tonic-gate 
804*0Sstevel@tonic-gate 	if (dsp->ds_vid == VLAN_ID_NONE ||
805*0Sstevel@tonic-gate 	    selp->dl_priority > (1 << VLAN_PRI_SIZE) - 1 ||
806*0Sstevel@tonic-gate 	    selp->dl_priority < 0) {
807*0Sstevel@tonic-gate 		dlerrorack(dsp->ds_wq, mp, DL_UDQOS_REQ, DL_BADQOSPARAM, 0);
808*0Sstevel@tonic-gate 		return (B_FALSE);
809*0Sstevel@tonic-gate 	}
810*0Sstevel@tonic-gate 
811*0Sstevel@tonic-gate 	dsp->ds_pri = selp->dl_priority;
812*0Sstevel@tonic-gate 	proto_udqos_ack(dsp, mp);
813*0Sstevel@tonic-gate 	return (B_TRUE);
814*0Sstevel@tonic-gate }
815*0Sstevel@tonic-gate 
816*0Sstevel@tonic-gate /*
817*0Sstevel@tonic-gate  * DL_CAPABILITY_REQ
818*0Sstevel@tonic-gate  */
819*0Sstevel@tonic-gate /*ARGSUSED*/
820*0Sstevel@tonic-gate static boolean_t
821*0Sstevel@tonic-gate proto_capability_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp)
822*0Sstevel@tonic-gate {
823*0Sstevel@tonic-gate 	dl_capability_req_t	*dlp = (dl_capability_req_t *)udlp;
824*0Sstevel@tonic-gate 
825*0Sstevel@tonic-gate 	if (dsp->ds_dlstate == DL_UNATTACHED ||
826*0Sstevel@tonic-gate 	    DL_ACK_PENDING(dsp->ds_dlstate)) {
827*0Sstevel@tonic-gate 		dlerrorack(dsp->ds_wq, mp, DL_CAPABILITY_REQ, DL_OUTSTATE,
828*0Sstevel@tonic-gate 		    0);
829*0Sstevel@tonic-gate 		return (B_FALSE);
830*0Sstevel@tonic-gate 	}
831*0Sstevel@tonic-gate 
832*0Sstevel@tonic-gate 	if (MBLKL(mp) < sizeof (dl_capability_req_t)) {
833*0Sstevel@tonic-gate 		dlerrorack(dsp->ds_wq, mp, DL_CAPABILITY_REQ, DL_BADPRIM, 0);
834*0Sstevel@tonic-gate 		return (B_FALSE);
835*0Sstevel@tonic-gate 	}
836*0Sstevel@tonic-gate 
837*0Sstevel@tonic-gate 	/*
838*0Sstevel@tonic-gate 	 * This request is overloaded. If there are no requested capabilities
839*0Sstevel@tonic-gate 	 * then we just want to acknowledge with all the capabilities we
840*0Sstevel@tonic-gate 	 * support. Otherwise we enable the set of capabilities requested.
841*0Sstevel@tonic-gate 	 */
842*0Sstevel@tonic-gate 	if (dlp->dl_sub_length == 0) {
843*0Sstevel@tonic-gate 		proto_capability_ack(dsp, mp);
844*0Sstevel@tonic-gate 		return (B_TRUE);
845*0Sstevel@tonic-gate 	}
846*0Sstevel@tonic-gate 
847*0Sstevel@tonic-gate 	if (!MBLKIN(mp, dlp->dl_sub_offset, dlp->dl_sub_length)) {
848*0Sstevel@tonic-gate 		dlerrorack(dsp->ds_wq, mp, DL_CAPABILITY_REQ, DL_BADPRIM, 0);
849*0Sstevel@tonic-gate 		return (B_FALSE);
850*0Sstevel@tonic-gate 	}
851*0Sstevel@tonic-gate 
852*0Sstevel@tonic-gate 	proto_capability_enable(dsp, mp);
853*0Sstevel@tonic-gate 	return (B_TRUE);
854*0Sstevel@tonic-gate }
855*0Sstevel@tonic-gate 
856*0Sstevel@tonic-gate /*
857*0Sstevel@tonic-gate  * DL_NOTIFY_REQ
858*0Sstevel@tonic-gate  */
859*0Sstevel@tonic-gate static boolean_t
860*0Sstevel@tonic-gate proto_notify_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp)
861*0Sstevel@tonic-gate {
862*0Sstevel@tonic-gate 	dl_notify_req_t		*dlp = (dl_notify_req_t *)udlp;
863*0Sstevel@tonic-gate 	uint_t			notifications =
864*0Sstevel@tonic-gate 	    DL_NOTE_PROMISC_ON_PHYS |
865*0Sstevel@tonic-gate 	    DL_NOTE_PROMISC_OFF_PHYS |
866*0Sstevel@tonic-gate 	    DL_NOTE_PHYS_ADDR |
867*0Sstevel@tonic-gate 	    DL_NOTE_LINK_UP |
868*0Sstevel@tonic-gate 	    DL_NOTE_LINK_DOWN |
869*0Sstevel@tonic-gate 	    DL_NOTE_CAPAB_RENEG;
870*0Sstevel@tonic-gate 
871*0Sstevel@tonic-gate 	if (dsp->ds_dlstate == DL_UNATTACHED ||
872*0Sstevel@tonic-gate 	    DL_ACK_PENDING(dsp->ds_dlstate)) {
873*0Sstevel@tonic-gate 		dlerrorack(dsp->ds_wq, mp, DL_NOTIFY_REQ, DL_OUTSTATE,
874*0Sstevel@tonic-gate 		    0);
875*0Sstevel@tonic-gate 		return (B_FALSE);
876*0Sstevel@tonic-gate 	}
877*0Sstevel@tonic-gate 
878*0Sstevel@tonic-gate 	if (MBLKL(mp) < sizeof (dl_notify_req_t)) {
879*0Sstevel@tonic-gate 		dlerrorack(dsp->ds_wq, mp, DL_NOTIFY_REQ, DL_BADPRIM, 0);
880*0Sstevel@tonic-gate 		return (B_FALSE);
881*0Sstevel@tonic-gate 	}
882*0Sstevel@tonic-gate 
883*0Sstevel@tonic-gate 	if (dsp->ds_mip->mi_stat[MAC_STAT_IFSPEED])
884*0Sstevel@tonic-gate 		notifications |= DL_NOTE_SPEED;
885*0Sstevel@tonic-gate 
886*0Sstevel@tonic-gate 	proto_notify_ack(dsp, mp, dlp->dl_notifications & notifications,
887*0Sstevel@tonic-gate 	    notifications);
888*0Sstevel@tonic-gate 	return (B_TRUE);
889*0Sstevel@tonic-gate }
890*0Sstevel@tonic-gate 
891*0Sstevel@tonic-gate /*
892*0Sstevel@tonic-gate  * DL_UINTDATA_REQ
893*0Sstevel@tonic-gate  */
894*0Sstevel@tonic-gate static boolean_t
895*0Sstevel@tonic-gate proto_unitdata_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp)
896*0Sstevel@tonic-gate {
897*0Sstevel@tonic-gate 	queue_t			*q = dsp->ds_wq;
898*0Sstevel@tonic-gate 	dl_unitdata_req_t	*dlp = (dl_unitdata_req_t *)udlp;
899*0Sstevel@tonic-gate 	off_t			off;
900*0Sstevel@tonic-gate 	size_t			len;
901*0Sstevel@tonic-gate 	size_t			size;
902*0Sstevel@tonic-gate 	const uint8_t		*addr;
903*0Sstevel@tonic-gate 	uint16_t		sap;
904*0Sstevel@tonic-gate 	uint_t			addr_length;
905*0Sstevel@tonic-gate 	mblk_t			*bp;
906*0Sstevel@tonic-gate 	mblk_t			*cont;
907*0Sstevel@tonic-gate 	uint32_t		start;
908*0Sstevel@tonic-gate 	uint32_t		stuff;
909*0Sstevel@tonic-gate 	uint32_t		end;
910*0Sstevel@tonic-gate 	uint32_t		value;
911*0Sstevel@tonic-gate 	uint32_t		flags;
912*0Sstevel@tonic-gate 
913*0Sstevel@tonic-gate 	if (dsp->ds_dlstate != DL_IDLE) {
914*0Sstevel@tonic-gate 		dlerrorack(q, mp, DL_UNITDATA_REQ, DL_OUTSTATE, 0);
915*0Sstevel@tonic-gate 		return (B_FALSE);
916*0Sstevel@tonic-gate 	}
917*0Sstevel@tonic-gate 
918*0Sstevel@tonic-gate 	if (MBLKL(mp) < sizeof (dl_unitdata_req_t) || mp->b_cont == NULL) {
919*0Sstevel@tonic-gate 		dlerrorack(q, mp, DL_UNITDATA_REQ, DL_BADPRIM, 0);
920*0Sstevel@tonic-gate 		return (B_FALSE);
921*0Sstevel@tonic-gate 	}
922*0Sstevel@tonic-gate 
923*0Sstevel@tonic-gate 	off = dlp->dl_dest_addr_offset;
924*0Sstevel@tonic-gate 	len = dlp->dl_dest_addr_length;
925*0Sstevel@tonic-gate 
926*0Sstevel@tonic-gate 	if (!MBLKIN(mp, off, len) || !IS_P2ALIGNED(off, sizeof (uint16_t))) {
927*0Sstevel@tonic-gate 		dlerrorack(q, mp, DL_UNITDATA_REQ, DL_BADPRIM, 0);
928*0Sstevel@tonic-gate 		return (B_FALSE);
929*0Sstevel@tonic-gate 	}
930*0Sstevel@tonic-gate 
931*0Sstevel@tonic-gate 	addr_length = dsp->ds_mip->mi_addr_length;
932*0Sstevel@tonic-gate 	if (len != addr_length + sizeof (uint16_t))
933*0Sstevel@tonic-gate 		goto badaddr;
934*0Sstevel@tonic-gate 
935*0Sstevel@tonic-gate 	addr = mp->b_rptr + off;
936*0Sstevel@tonic-gate 	sap = *(uint16_t *)(mp->b_rptr + off + addr_length);
937*0Sstevel@tonic-gate 
938*0Sstevel@tonic-gate 	/*
939*0Sstevel@tonic-gate 	 * Check the length of the packet and the block types.
940*0Sstevel@tonic-gate 	 */
941*0Sstevel@tonic-gate 	size = 0;
942*0Sstevel@tonic-gate 	cont = mp->b_cont;
943*0Sstevel@tonic-gate 	for (bp = cont; bp != NULL; bp = bp->b_cont) {
944*0Sstevel@tonic-gate 		if (DB_TYPE(bp) != M_DATA)
945*0Sstevel@tonic-gate 			goto baddata;
946*0Sstevel@tonic-gate 
947*0Sstevel@tonic-gate 		size += MBLKL(bp);
948*0Sstevel@tonic-gate 	}
949*0Sstevel@tonic-gate 
950*0Sstevel@tonic-gate 	if (size > dsp->ds_mip->mi_sdu_max)
951*0Sstevel@tonic-gate 		goto baddata;
952*0Sstevel@tonic-gate 
953*0Sstevel@tonic-gate 	/*
954*0Sstevel@tonic-gate 	 * Build a packet header.
955*0Sstevel@tonic-gate 	 */
956*0Sstevel@tonic-gate 	if ((bp = dls_header(dsp->ds_dc, addr, sap, dsp->ds_pri)) == NULL)
957*0Sstevel@tonic-gate 		goto badaddr;
958*0Sstevel@tonic-gate 
959*0Sstevel@tonic-gate 	/*
960*0Sstevel@tonic-gate 	 * We no longer need the M_PROTO header, so free it.
961*0Sstevel@tonic-gate 	 */
962*0Sstevel@tonic-gate 	freeb(mp);
963*0Sstevel@tonic-gate 
964*0Sstevel@tonic-gate 	/*
965*0Sstevel@tonic-gate 	 * Transfer the checksum offload information if it is present.
966*0Sstevel@tonic-gate 	 */
967*0Sstevel@tonic-gate 	hcksum_retrieve(cont, NULL, NULL, &start, &stuff, &end, &value,
968*0Sstevel@tonic-gate 	    &flags);
969*0Sstevel@tonic-gate 	(void) hcksum_assoc(bp, NULL, NULL, start, stuff, end, value, flags,
970*0Sstevel@tonic-gate 	    0);
971*0Sstevel@tonic-gate 
972*0Sstevel@tonic-gate 	/*
973*0Sstevel@tonic-gate 	 * Link the payload onto the new header.
974*0Sstevel@tonic-gate 	 */
975*0Sstevel@tonic-gate 	ASSERT(bp->b_cont == NULL);
976*0Sstevel@tonic-gate 	bp->b_cont = cont;
977*0Sstevel@tonic-gate 
978*0Sstevel@tonic-gate 	/*
979*0Sstevel@tonic-gate 	 * If something is already queued then we must queue to avoid
980*0Sstevel@tonic-gate 	 * re-ordering.
981*0Sstevel@tonic-gate 	 */
982*0Sstevel@tonic-gate 	if (q->q_first != NULL) {
983*0Sstevel@tonic-gate 		(void) putq(q, bp);
984*0Sstevel@tonic-gate 		return (B_TRUE);
985*0Sstevel@tonic-gate 	}
986*0Sstevel@tonic-gate 
987*0Sstevel@tonic-gate 	/*
988*0Sstevel@tonic-gate 	 * Attempt to transmit the packet.
989*0Sstevel@tonic-gate 	 */
990*0Sstevel@tonic-gate 	if ((mp = dls_tx(dsp->ds_dc, bp)) != NULL) {
991*0Sstevel@tonic-gate 		noenable(q);
992*0Sstevel@tonic-gate 		while ((bp = mp) != NULL) {
993*0Sstevel@tonic-gate 			mp = mp->b_next;
994*0Sstevel@tonic-gate 			bp->b_next = NULL;
995*0Sstevel@tonic-gate 			(void) putq(q, bp);
996*0Sstevel@tonic-gate 		}
997*0Sstevel@tonic-gate 	}
998*0Sstevel@tonic-gate 	return (B_TRUE);
999*0Sstevel@tonic-gate 
1000*0Sstevel@tonic-gate badaddr:
1001*0Sstevel@tonic-gate 	dlerrorack(q, mp, DL_UNITDATA_REQ, DL_BADADDR, 0);
1002*0Sstevel@tonic-gate 	return (B_FALSE);
1003*0Sstevel@tonic-gate 
1004*0Sstevel@tonic-gate baddata:
1005*0Sstevel@tonic-gate 	dluderrorind(q, mp, (void *)addr, len, DL_BADDATA, 0);
1006*0Sstevel@tonic-gate 	return (B_FALSE);
1007*0Sstevel@tonic-gate }
1008*0Sstevel@tonic-gate 
1009*0Sstevel@tonic-gate /*
1010*0Sstevel@tonic-gate  * DL_PASSIVE_REQ
1011*0Sstevel@tonic-gate  */
1012*0Sstevel@tonic-gate /* ARGSUSED */
1013*0Sstevel@tonic-gate static boolean_t
1014*0Sstevel@tonic-gate proto_passive_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp)
1015*0Sstevel@tonic-gate {
1016*0Sstevel@tonic-gate 	ASSERT(PERIM_EXCL(dsp->ds_wq));
1017*0Sstevel@tonic-gate 
1018*0Sstevel@tonic-gate 	/*
1019*0Sstevel@tonic-gate 	 * If we've already become active by issuing an active primitive,
1020*0Sstevel@tonic-gate 	 * then it's too late to try to become passive.
1021*0Sstevel@tonic-gate 	 */
1022*0Sstevel@tonic-gate 	if (dsp->ds_passivestate == DLD_ACTIVE) {
1023*0Sstevel@tonic-gate 		dlerrorack(dsp->ds_wq, mp, DL_PASSIVE_REQ, DL_OUTSTATE, 0);
1024*0Sstevel@tonic-gate 		return (B_FALSE);
1025*0Sstevel@tonic-gate 	}
1026*0Sstevel@tonic-gate 
1027*0Sstevel@tonic-gate 	if (MBLKL(mp) < sizeof (dl_passive_req_t)) {
1028*0Sstevel@tonic-gate 		dlerrorack(dsp->ds_wq, mp, DL_PASSIVE_REQ, DL_BADPRIM, 0);
1029*0Sstevel@tonic-gate 		return (B_FALSE);
1030*0Sstevel@tonic-gate 	}
1031*0Sstevel@tonic-gate 
1032*0Sstevel@tonic-gate 	dsp->ds_passivestate = DLD_PASSIVE;
1033*0Sstevel@tonic-gate 	dlokack(dsp->ds_wq, mp, DL_PASSIVE_REQ);
1034*0Sstevel@tonic-gate 	return (B_TRUE);
1035*0Sstevel@tonic-gate }
1036*0Sstevel@tonic-gate 
1037*0Sstevel@tonic-gate /*
1038*0Sstevel@tonic-gate  * Catch-all handler.
1039*0Sstevel@tonic-gate  */
1040*0Sstevel@tonic-gate static boolean_t
1041*0Sstevel@tonic-gate proto_req(dld_str_t *dsp, union DL_primitives *dlp, mblk_t *mp)
1042*0Sstevel@tonic-gate {
1043*0Sstevel@tonic-gate 	dlerrorack(dsp->ds_wq, mp, dlp->dl_primitive, DL_UNSUPPORTED, 0);
1044*0Sstevel@tonic-gate 	return (B_FALSE);
1045*0Sstevel@tonic-gate }
1046*0Sstevel@tonic-gate 
1047*0Sstevel@tonic-gate typedef struct dl_info_ack_wrapper {
1048*0Sstevel@tonic-gate 	dl_info_ack_t		dl_info;
1049*0Sstevel@tonic-gate 	uint8_t			dl_addr[MAXADDRLEN + sizeof (uint16_t)];
1050*0Sstevel@tonic-gate 	uint8_t			dl_brdcst_addr[MAXADDRLEN];
1051*0Sstevel@tonic-gate 	dl_qos_cl_range1_t	dl_qos_range1;
1052*0Sstevel@tonic-gate 	dl_qos_cl_sel1_t	dl_qos_sel1;
1053*0Sstevel@tonic-gate } dl_info_ack_wrapper_t;
1054*0Sstevel@tonic-gate 
1055*0Sstevel@tonic-gate #define	NEG(x)	-(x)
1056*0Sstevel@tonic-gate 
1057*0Sstevel@tonic-gate /*
1058*0Sstevel@tonic-gate  * DL_INFO_ACK
1059*0Sstevel@tonic-gate  */
1060*0Sstevel@tonic-gate static void
1061*0Sstevel@tonic-gate proto_info_ack(dld_str_t *dsp, mblk_t *mp)
1062*0Sstevel@tonic-gate {
1063*0Sstevel@tonic-gate 	dl_info_ack_wrapper_t	*dlwp;
1064*0Sstevel@tonic-gate 	dl_info_ack_t		*dlp;
1065*0Sstevel@tonic-gate 	dl_qos_cl_sel1_t	*selp;
1066*0Sstevel@tonic-gate 	dl_qos_cl_range1_t	*rangep;
1067*0Sstevel@tonic-gate 	uint8_t			*addr;
1068*0Sstevel@tonic-gate 	uint8_t			*brdcst_addr;
1069*0Sstevel@tonic-gate 	dld_node_t		*dnp;
1070*0Sstevel@tonic-gate 	uint_t			addr_length;
1071*0Sstevel@tonic-gate 	uint_t			sap_length;
1072*0Sstevel@tonic-gate 
1073*0Sstevel@tonic-gate 	/*
1074*0Sstevel@tonic-gate 	 * Swap the request message for one large enough to contain the
1075*0Sstevel@tonic-gate 	 * wrapper structure defined above.
1076*0Sstevel@tonic-gate 	 */
1077*0Sstevel@tonic-gate 	if ((mp = mexchange(dsp->ds_wq, mp, sizeof (dl_info_ack_wrapper_t),
1078*0Sstevel@tonic-gate 	    M_PCPROTO, 0)) == NULL)
1079*0Sstevel@tonic-gate 		return;
1080*0Sstevel@tonic-gate 
1081*0Sstevel@tonic-gate 	bzero(mp->b_rptr, sizeof (dl_info_ack_wrapper_t));
1082*0Sstevel@tonic-gate 	dlwp = (dl_info_ack_wrapper_t *)mp->b_rptr;
1083*0Sstevel@tonic-gate 
1084*0Sstevel@tonic-gate 	dlp = &(dlwp->dl_info);
1085*0Sstevel@tonic-gate 	ASSERT(dlp == (dl_info_ack_t *)mp->b_rptr);
1086*0Sstevel@tonic-gate 
1087*0Sstevel@tonic-gate 	dlp->dl_primitive = DL_INFO_ACK;
1088*0Sstevel@tonic-gate 
1089*0Sstevel@tonic-gate 	/*
1090*0Sstevel@tonic-gate 	 * Set up the sub-structure pointers.
1091*0Sstevel@tonic-gate 	 */
1092*0Sstevel@tonic-gate 	addr = dlwp->dl_addr;
1093*0Sstevel@tonic-gate 	brdcst_addr = dlwp->dl_brdcst_addr;
1094*0Sstevel@tonic-gate 	rangep = &(dlwp->dl_qos_range1);
1095*0Sstevel@tonic-gate 	selp = &(dlwp->dl_qos_sel1);
1096*0Sstevel@tonic-gate 
1097*0Sstevel@tonic-gate 	/*
1098*0Sstevel@tonic-gate 	 * This driver supports only version 2 connectionless DLPI provider
1099*0Sstevel@tonic-gate 	 * nodes.
1100*0Sstevel@tonic-gate 	 */
1101*0Sstevel@tonic-gate 	dlp->dl_service_mode = DL_CLDLS;
1102*0Sstevel@tonic-gate 	dlp->dl_version = DL_VERSION_2;
1103*0Sstevel@tonic-gate 
1104*0Sstevel@tonic-gate 	/*
1105*0Sstevel@tonic-gate 	 * Set the style of the provider from the dld_node_t structure
1106*0Sstevel@tonic-gate 	 * representing the dev_t that was opened.
1107*0Sstevel@tonic-gate 	 */
1108*0Sstevel@tonic-gate 	dnp = dsp->ds_dnp;
1109*0Sstevel@tonic-gate 	dlp->dl_provider_style = dnp->dn_style;
1110*0Sstevel@tonic-gate 	ASSERT(dlp->dl_provider_style == DL_STYLE1 ||
1111*0Sstevel@tonic-gate 	    dlp->dl_provider_style == DL_STYLE2);
1112*0Sstevel@tonic-gate 
1113*0Sstevel@tonic-gate 	/*
1114*0Sstevel@tonic-gate 	 * Set the current DLPI state.
1115*0Sstevel@tonic-gate 	 */
1116*0Sstevel@tonic-gate 	dlp->dl_current_state = dsp->ds_dlstate;
1117*0Sstevel@tonic-gate 
1118*0Sstevel@tonic-gate 	/*
1119*0Sstevel@tonic-gate 	 * Gratuitously set the media type. This is because the Cisco VPN 3000
1120*0Sstevel@tonic-gate 	 * module assumes that the media type is known prior to DL_ATTACH_REQ
1121*0Sstevel@tonic-gate 	 * being completed.
1122*0Sstevel@tonic-gate 	 */
1123*0Sstevel@tonic-gate 	dlp->dl_mac_type = DL_ETHER;
1124*0Sstevel@tonic-gate 
1125*0Sstevel@tonic-gate 	/*
1126*0Sstevel@tonic-gate 	 * If the stream is not at least attached then we're done.
1127*0Sstevel@tonic-gate 	 */
1128*0Sstevel@tonic-gate 	if (dsp->ds_dlstate == DL_UNATTACHED ||
1129*0Sstevel@tonic-gate 	    dsp->ds_dlstate == DL_ATTACH_PENDING ||
1130*0Sstevel@tonic-gate 	    dsp->ds_dlstate == DL_DETACH_PENDING)
1131*0Sstevel@tonic-gate 		goto done;
1132*0Sstevel@tonic-gate 
1133*0Sstevel@tonic-gate 	/*
1134*0Sstevel@tonic-gate 	 * Set the media type (properly this time).
1135*0Sstevel@tonic-gate 	 */
1136*0Sstevel@tonic-gate 	dlp->dl_mac_type = dsp->ds_mip->mi_media;
1137*0Sstevel@tonic-gate 
1138*0Sstevel@tonic-gate 	/*
1139*0Sstevel@tonic-gate 	 * Set the DLSAP length. We only support 16 bit values and they
1140*0Sstevel@tonic-gate 	 * appear after the MAC address portion of DLSAP addresses.
1141*0Sstevel@tonic-gate 	 */
1142*0Sstevel@tonic-gate 	sap_length = sizeof (uint16_t);
1143*0Sstevel@tonic-gate 	dlp->dl_sap_length = NEG(sap_length);
1144*0Sstevel@tonic-gate 
1145*0Sstevel@tonic-gate 	/*
1146*0Sstevel@tonic-gate 	 * Set the minimum and maximum payload sizes.
1147*0Sstevel@tonic-gate 	 */
1148*0Sstevel@tonic-gate 	dlp->dl_min_sdu = dsp->ds_mip->mi_sdu_min;
1149*0Sstevel@tonic-gate 	dlp->dl_max_sdu = dsp->ds_mip->mi_sdu_max;
1150*0Sstevel@tonic-gate 
1151*0Sstevel@tonic-gate 	addr_length = dsp->ds_mip->mi_addr_length;
1152*0Sstevel@tonic-gate 	ASSERT(addr_length != 0);
1153*0Sstevel@tonic-gate 
1154*0Sstevel@tonic-gate 	/*
1155*0Sstevel@tonic-gate 	 * Copy in the media broadcast address.
1156*0Sstevel@tonic-gate 	 */
1157*0Sstevel@tonic-gate 	dlp->dl_brdcst_addr_offset = (uintptr_t)brdcst_addr - (uintptr_t)dlp;
1158*0Sstevel@tonic-gate 	bcopy(dsp->ds_mip->mi_brdcst_addr, brdcst_addr, addr_length);
1159*0Sstevel@tonic-gate 	dlp->dl_brdcst_addr_length = addr_length;
1160*0Sstevel@tonic-gate 
1161*0Sstevel@tonic-gate 	/*
1162*0Sstevel@tonic-gate 	 * We only support QoS information for VLAN interfaces.
1163*0Sstevel@tonic-gate 	 */
1164*0Sstevel@tonic-gate 	if (dsp->ds_vid != VLAN_ID_NONE) {
1165*0Sstevel@tonic-gate 		dlp->dl_qos_range_offset = (uintptr_t)rangep - (uintptr_t)dlp;
1166*0Sstevel@tonic-gate 		dlp->dl_qos_range_length = sizeof (dl_qos_cl_range1_t);
1167*0Sstevel@tonic-gate 
1168*0Sstevel@tonic-gate 		rangep->dl_qos_type = DL_QOS_CL_RANGE1;
1169*0Sstevel@tonic-gate 		rangep->dl_trans_delay.dl_target_value = DL_UNKNOWN;
1170*0Sstevel@tonic-gate 		rangep->dl_trans_delay.dl_accept_value = DL_UNKNOWN;
1171*0Sstevel@tonic-gate 		rangep->dl_protection.dl_min = DL_UNKNOWN;
1172*0Sstevel@tonic-gate 		rangep->dl_protection.dl_max = DL_UNKNOWN;
1173*0Sstevel@tonic-gate 		rangep->dl_residual_error = DL_UNKNOWN;
1174*0Sstevel@tonic-gate 
1175*0Sstevel@tonic-gate 		/*
1176*0Sstevel@tonic-gate 		 * Specify the supported range of priorities.
1177*0Sstevel@tonic-gate 		 */
1178*0Sstevel@tonic-gate 		rangep->dl_priority.dl_min = 0;
1179*0Sstevel@tonic-gate 		rangep->dl_priority.dl_max = (1 << VLAN_PRI_SIZE) - 1;
1180*0Sstevel@tonic-gate 
1181*0Sstevel@tonic-gate 		dlp->dl_qos_offset = (uintptr_t)selp - (uintptr_t)dlp;
1182*0Sstevel@tonic-gate 		dlp->dl_qos_length = sizeof (dl_qos_cl_sel1_t);
1183*0Sstevel@tonic-gate 
1184*0Sstevel@tonic-gate 		selp->dl_qos_type = DL_QOS_CL_SEL1;
1185*0Sstevel@tonic-gate 		selp->dl_trans_delay = DL_UNKNOWN;
1186*0Sstevel@tonic-gate 		selp->dl_protection = DL_UNKNOWN;
1187*0Sstevel@tonic-gate 		selp->dl_residual_error = DL_UNKNOWN;
1188*0Sstevel@tonic-gate 
1189*0Sstevel@tonic-gate 		/*
1190*0Sstevel@tonic-gate 		 * Specify the current priority (which can be changed by
1191*0Sstevel@tonic-gate 		 * the DL_UDQOS_REQ primitive).
1192*0Sstevel@tonic-gate 		 */
1193*0Sstevel@tonic-gate 		selp->dl_priority = dsp->ds_pri;
1194*0Sstevel@tonic-gate 	} else {
1195*0Sstevel@tonic-gate 		/*
1196*0Sstevel@tonic-gate 		 * Shorten the buffer to lose the unused QoS information
1197*0Sstevel@tonic-gate 		 * structures. This is to work around a bug in the Cisco VPN
1198*0Sstevel@tonic-gate 		 * 3000 module.
1199*0Sstevel@tonic-gate 		 */
1200*0Sstevel@tonic-gate 		mp->b_wptr = (uint8_t *)rangep;
1201*0Sstevel@tonic-gate 	}
1202*0Sstevel@tonic-gate 
1203*0Sstevel@tonic-gate 	dlp->dl_addr_length = addr_length + sizeof (uint16_t);
1204*0Sstevel@tonic-gate 	if (dsp->ds_dlstate == DL_IDLE) {
1205*0Sstevel@tonic-gate 		/*
1206*0Sstevel@tonic-gate 		 * The stream is bound. Therefore we can formulate a valid
1207*0Sstevel@tonic-gate 		 * DLSAP address.
1208*0Sstevel@tonic-gate 		 */
1209*0Sstevel@tonic-gate 		dlp->dl_addr_offset = (uintptr_t)addr - (uintptr_t)dlp;
1210*0Sstevel@tonic-gate 		bcopy(dsp->ds_curr_addr, addr, addr_length);
1211*0Sstevel@tonic-gate 		*(uint16_t *)(addr + addr_length) = dsp->ds_sap;
1212*0Sstevel@tonic-gate 	}
1213*0Sstevel@tonic-gate 
1214*0Sstevel@tonic-gate done:
1215*0Sstevel@tonic-gate 	ASSERT(IMPLY(dlp->dl_qos_offset != 0, dlp->dl_qos_length != 0));
1216*0Sstevel@tonic-gate 	ASSERT(IMPLY(dlp->dl_qos_range_offset != 0,
1217*0Sstevel@tonic-gate 	    dlp->dl_qos_range_length != 0));
1218*0Sstevel@tonic-gate 	ASSERT(IMPLY(dlp->dl_addr_offset != 0, dlp->dl_addr_length != 0));
1219*0Sstevel@tonic-gate 	ASSERT(IMPLY(dlp->dl_brdcst_addr_offset != 0,
1220*0Sstevel@tonic-gate 	    dlp->dl_brdcst_addr_length != 0));
1221*0Sstevel@tonic-gate 
1222*0Sstevel@tonic-gate 	qreply(dsp->ds_wq, mp);
1223*0Sstevel@tonic-gate }
1224*0Sstevel@tonic-gate 
1225*0Sstevel@tonic-gate /*
1226*0Sstevel@tonic-gate  * DL_OK_ACK/DL_ERROR_ACK
1227*0Sstevel@tonic-gate  */
1228*0Sstevel@tonic-gate static void
1229*0Sstevel@tonic-gate proto_attach_ack(dld_str_t *dsp, mblk_t *mp, int err)
1230*0Sstevel@tonic-gate {
1231*0Sstevel@tonic-gate 	int		dl_err;
1232*0Sstevel@tonic-gate 
1233*0Sstevel@tonic-gate 	if (err != 0)
1234*0Sstevel@tonic-gate 		goto failed;
1235*0Sstevel@tonic-gate 
1236*0Sstevel@tonic-gate 	dsp->ds_dlstate = DL_UNBOUND;
1237*0Sstevel@tonic-gate 	dlokack(dsp->ds_wq, mp, DL_ATTACH_REQ);
1238*0Sstevel@tonic-gate 	return;
1239*0Sstevel@tonic-gate 
1240*0Sstevel@tonic-gate failed:
1241*0Sstevel@tonic-gate 	switch (err) {
1242*0Sstevel@tonic-gate 	case ENOENT:
1243*0Sstevel@tonic-gate 		dl_err = DL_BADPPA;
1244*0Sstevel@tonic-gate 		err = 0;
1245*0Sstevel@tonic-gate 		break;
1246*0Sstevel@tonic-gate 
1247*0Sstevel@tonic-gate 	default:
1248*0Sstevel@tonic-gate 		dl_err = DL_SYSERR;
1249*0Sstevel@tonic-gate 		break;
1250*0Sstevel@tonic-gate 	}
1251*0Sstevel@tonic-gate 
1252*0Sstevel@tonic-gate 	dsp->ds_dlstate = DL_UNATTACHED;
1253*0Sstevel@tonic-gate 	dlerrorack(dsp->ds_wq, mp, DL_ATTACH_REQ, dl_err, err);
1254*0Sstevel@tonic-gate }
1255*0Sstevel@tonic-gate 
1256*0Sstevel@tonic-gate /*
1257*0Sstevel@tonic-gate  * DL_OK_ACK
1258*0Sstevel@tonic-gate  */
1259*0Sstevel@tonic-gate static void
1260*0Sstevel@tonic-gate proto_detach_ack(dld_str_t *dsp, mblk_t *mp)
1261*0Sstevel@tonic-gate {
1262*0Sstevel@tonic-gate 	dsp->ds_dlstate = DL_UNATTACHED;
1263*0Sstevel@tonic-gate 	dlokack(dsp->ds_wq, mp, DL_DETACH_REQ);
1264*0Sstevel@tonic-gate }
1265*0Sstevel@tonic-gate 
1266*0Sstevel@tonic-gate /*
1267*0Sstevel@tonic-gate  * DL_BIND_ACK/DL_ERROR_ACK
1268*0Sstevel@tonic-gate  */
1269*0Sstevel@tonic-gate static void
1270*0Sstevel@tonic-gate proto_bind_ack(dld_str_t *dsp, mblk_t *mp, int err)
1271*0Sstevel@tonic-gate {
1272*0Sstevel@tonic-gate 	uint8_t			addr[MAXADDRLEN];
1273*0Sstevel@tonic-gate 	uint_t			addr_length;
1274*0Sstevel@tonic-gate 	int			dl_err;
1275*0Sstevel@tonic-gate 
1276*0Sstevel@tonic-gate 	if (err != 0)
1277*0Sstevel@tonic-gate 		goto failed;
1278*0Sstevel@tonic-gate 
1279*0Sstevel@tonic-gate 	/*
1280*0Sstevel@tonic-gate 	 * Copy in MAC address.
1281*0Sstevel@tonic-gate 	 */
1282*0Sstevel@tonic-gate 	addr_length = dsp->ds_mip->mi_addr_length;
1283*0Sstevel@tonic-gate 	bcopy(dsp->ds_curr_addr, addr, addr_length);
1284*0Sstevel@tonic-gate 
1285*0Sstevel@tonic-gate 	/*
1286*0Sstevel@tonic-gate 	 * Copy in the DLSAP.
1287*0Sstevel@tonic-gate 	 */
1288*0Sstevel@tonic-gate 	*(uint16_t *)(addr + addr_length) = dsp->ds_sap;
1289*0Sstevel@tonic-gate 	addr_length += sizeof (uint16_t);
1290*0Sstevel@tonic-gate 
1291*0Sstevel@tonic-gate 	dsp->ds_dlstate = DL_IDLE;
1292*0Sstevel@tonic-gate 	dlbindack(dsp->ds_wq, mp, dsp->ds_sap, (void *)addr, addr_length, 0,
1293*0Sstevel@tonic-gate 	    0);
1294*0Sstevel@tonic-gate 	return;
1295*0Sstevel@tonic-gate 
1296*0Sstevel@tonic-gate failed:
1297*0Sstevel@tonic-gate 	switch (err) {
1298*0Sstevel@tonic-gate 	case EINVAL:
1299*0Sstevel@tonic-gate 		dl_err = DL_BADADDR;
1300*0Sstevel@tonic-gate 		err = 0;
1301*0Sstevel@tonic-gate 		break;
1302*0Sstevel@tonic-gate 
1303*0Sstevel@tonic-gate 	default:
1304*0Sstevel@tonic-gate 		dl_err = DL_SYSERR;
1305*0Sstevel@tonic-gate 		break;
1306*0Sstevel@tonic-gate 	}
1307*0Sstevel@tonic-gate 
1308*0Sstevel@tonic-gate 	dsp->ds_dlstate = DL_UNBOUND;
1309*0Sstevel@tonic-gate 	dlerrorack(dsp->ds_wq, mp, DL_BIND_REQ, dl_err, err);
1310*0Sstevel@tonic-gate }
1311*0Sstevel@tonic-gate 
1312*0Sstevel@tonic-gate /*
1313*0Sstevel@tonic-gate  * DL_OK_ACK
1314*0Sstevel@tonic-gate  */
1315*0Sstevel@tonic-gate static void
1316*0Sstevel@tonic-gate proto_unbind_ack(dld_str_t *dsp, mblk_t *mp)
1317*0Sstevel@tonic-gate {
1318*0Sstevel@tonic-gate 	dsp->ds_dlstate = DL_UNBOUND;
1319*0Sstevel@tonic-gate 	dlokack(dsp->ds_wq, mp, DL_UNBIND_REQ);
1320*0Sstevel@tonic-gate }
1321*0Sstevel@tonic-gate 
1322*0Sstevel@tonic-gate /*
1323*0Sstevel@tonic-gate  * DL_OK_ACK/DL_ERROR_ACK
1324*0Sstevel@tonic-gate  */
1325*0Sstevel@tonic-gate static void
1326*0Sstevel@tonic-gate proto_promiscon_ack(dld_str_t *dsp, mblk_t *mp, int err)
1327*0Sstevel@tonic-gate {
1328*0Sstevel@tonic-gate 	if (err != 0)
1329*0Sstevel@tonic-gate 		goto failed;
1330*0Sstevel@tonic-gate 
1331*0Sstevel@tonic-gate 	dlokack(dsp->ds_wq, mp, DL_PROMISCON_REQ);
1332*0Sstevel@tonic-gate 	return;
1333*0Sstevel@tonic-gate 
1334*0Sstevel@tonic-gate failed:
1335*0Sstevel@tonic-gate 	dlerrorack(dsp->ds_wq, mp, DL_PROMISCON_REQ, DL_SYSERR, err);
1336*0Sstevel@tonic-gate }
1337*0Sstevel@tonic-gate 
1338*0Sstevel@tonic-gate /*
1339*0Sstevel@tonic-gate  * DL_OK_ACK/DL_ERROR_ACK
1340*0Sstevel@tonic-gate  */
1341*0Sstevel@tonic-gate static void
1342*0Sstevel@tonic-gate proto_promiscoff_ack(dld_str_t *dsp, mblk_t *mp, int err)
1343*0Sstevel@tonic-gate {
1344*0Sstevel@tonic-gate 	if (err != 0)
1345*0Sstevel@tonic-gate 		goto failed;
1346*0Sstevel@tonic-gate 
1347*0Sstevel@tonic-gate 	dlokack(dsp->ds_wq, mp, DL_PROMISCOFF_REQ);
1348*0Sstevel@tonic-gate 	return;
1349*0Sstevel@tonic-gate 
1350*0Sstevel@tonic-gate failed:
1351*0Sstevel@tonic-gate 	dlerrorack(dsp->ds_wq, mp, DL_PROMISCOFF_REQ, DL_SYSERR, err);
1352*0Sstevel@tonic-gate }
1353*0Sstevel@tonic-gate 
1354*0Sstevel@tonic-gate /*
1355*0Sstevel@tonic-gate  * DL_OK_ACK/DL_ERROR_ACK
1356*0Sstevel@tonic-gate  */
1357*0Sstevel@tonic-gate static void
1358*0Sstevel@tonic-gate proto_enabmulti_ack(dld_str_t *dsp, mblk_t *mp, int err)
1359*0Sstevel@tonic-gate {
1360*0Sstevel@tonic-gate 	int		dl_err;
1361*0Sstevel@tonic-gate 
1362*0Sstevel@tonic-gate 	if (err != 0)
1363*0Sstevel@tonic-gate 		goto failed;
1364*0Sstevel@tonic-gate 
1365*0Sstevel@tonic-gate 	dlokack(dsp->ds_wq, mp, DL_ENABMULTI_REQ);
1366*0Sstevel@tonic-gate 	return;
1367*0Sstevel@tonic-gate 
1368*0Sstevel@tonic-gate failed:
1369*0Sstevel@tonic-gate 	switch (err) {
1370*0Sstevel@tonic-gate 	case EINVAL:
1371*0Sstevel@tonic-gate 		dl_err = DL_BADADDR;
1372*0Sstevel@tonic-gate 		err = 0;
1373*0Sstevel@tonic-gate 		break;
1374*0Sstevel@tonic-gate 
1375*0Sstevel@tonic-gate 	case ENOSPC:
1376*0Sstevel@tonic-gate 		dl_err = DL_TOOMANY;
1377*0Sstevel@tonic-gate 		err = 0;
1378*0Sstevel@tonic-gate 		break;
1379*0Sstevel@tonic-gate 
1380*0Sstevel@tonic-gate 	default:
1381*0Sstevel@tonic-gate 		dl_err = DL_SYSERR;
1382*0Sstevel@tonic-gate 		break;
1383*0Sstevel@tonic-gate 	}
1384*0Sstevel@tonic-gate 
1385*0Sstevel@tonic-gate 	dlerrorack(dsp->ds_wq, mp, DL_ENABMULTI_REQ, dl_err, err);
1386*0Sstevel@tonic-gate }
1387*0Sstevel@tonic-gate 
1388*0Sstevel@tonic-gate /*
1389*0Sstevel@tonic-gate  * DL_OK_ACK/DL_ERROR_ACK
1390*0Sstevel@tonic-gate  */
1391*0Sstevel@tonic-gate static void
1392*0Sstevel@tonic-gate proto_disabmulti_ack(dld_str_t *dsp, mblk_t *mp, int err)
1393*0Sstevel@tonic-gate {
1394*0Sstevel@tonic-gate 	int		dl_err;
1395*0Sstevel@tonic-gate 
1396*0Sstevel@tonic-gate 	if (err != 0)
1397*0Sstevel@tonic-gate 		goto failed;
1398*0Sstevel@tonic-gate 
1399*0Sstevel@tonic-gate 	dlokack(dsp->ds_wq, mp, DL_DISABMULTI_REQ);
1400*0Sstevel@tonic-gate 	return;
1401*0Sstevel@tonic-gate 
1402*0Sstevel@tonic-gate failed:
1403*0Sstevel@tonic-gate 	switch (err) {
1404*0Sstevel@tonic-gate 	case EINVAL:
1405*0Sstevel@tonic-gate 		dl_err = DL_BADADDR;
1406*0Sstevel@tonic-gate 		err = 0;
1407*0Sstevel@tonic-gate 		break;
1408*0Sstevel@tonic-gate 
1409*0Sstevel@tonic-gate 	case ENOENT:
1410*0Sstevel@tonic-gate 		dl_err = DL_NOTENAB;
1411*0Sstevel@tonic-gate 		err = 0;
1412*0Sstevel@tonic-gate 		break;
1413*0Sstevel@tonic-gate 
1414*0Sstevel@tonic-gate 	default:
1415*0Sstevel@tonic-gate 		dl_err = DL_SYSERR;
1416*0Sstevel@tonic-gate 		break;
1417*0Sstevel@tonic-gate 	}
1418*0Sstevel@tonic-gate 
1419*0Sstevel@tonic-gate 	dlerrorack(dsp->ds_wq, mp, DL_DISABMULTI_REQ, dl_err, err);
1420*0Sstevel@tonic-gate }
1421*0Sstevel@tonic-gate 
1422*0Sstevel@tonic-gate /*
1423*0Sstevel@tonic-gate  * DL_PHYS_ADDR_ACK
1424*0Sstevel@tonic-gate  */
1425*0Sstevel@tonic-gate static void
1426*0Sstevel@tonic-gate proto_physaddr_ack(dld_str_t *dsp, mblk_t *mp, t_uscalar_t type)
1427*0Sstevel@tonic-gate {
1428*0Sstevel@tonic-gate 	uint_t			addr_length;
1429*0Sstevel@tonic-gate 
1430*0Sstevel@tonic-gate 	/*
1431*0Sstevel@tonic-gate 	 * Copy in the address.
1432*0Sstevel@tonic-gate 	 */
1433*0Sstevel@tonic-gate 	addr_length = dsp->ds_mip->mi_addr_length;
1434*0Sstevel@tonic-gate 	dlphysaddrack(dsp->ds_wq, mp, (type == DL_CURR_PHYS_ADDR) ?
1435*0Sstevel@tonic-gate 	    dsp->ds_curr_addr : dsp->ds_fact_addr, addr_length);
1436*0Sstevel@tonic-gate }
1437*0Sstevel@tonic-gate 
1438*0Sstevel@tonic-gate /*
1439*0Sstevel@tonic-gate  * DL_OK_ACK/DL_ERROR_ACK
1440*0Sstevel@tonic-gate  */
1441*0Sstevel@tonic-gate static void
1442*0Sstevel@tonic-gate proto_setphysaddr_ack(dld_str_t *dsp, mblk_t *mp, int err)
1443*0Sstevel@tonic-gate {
1444*0Sstevel@tonic-gate 	int		dl_err;
1445*0Sstevel@tonic-gate 
1446*0Sstevel@tonic-gate 	if (err != 0)
1447*0Sstevel@tonic-gate 		goto failed;
1448*0Sstevel@tonic-gate 
1449*0Sstevel@tonic-gate 	dlokack(dsp->ds_wq, mp, DL_SET_PHYS_ADDR_REQ);
1450*0Sstevel@tonic-gate 	return;
1451*0Sstevel@tonic-gate 
1452*0Sstevel@tonic-gate failed:
1453*0Sstevel@tonic-gate 	switch (err) {
1454*0Sstevel@tonic-gate 	case EINVAL:
1455*0Sstevel@tonic-gate 		dl_err = DL_BADADDR;
1456*0Sstevel@tonic-gate 		err = 0;
1457*0Sstevel@tonic-gate 		break;
1458*0Sstevel@tonic-gate 
1459*0Sstevel@tonic-gate 	default:
1460*0Sstevel@tonic-gate 		dl_err = DL_SYSERR;
1461*0Sstevel@tonic-gate 		break;
1462*0Sstevel@tonic-gate 	}
1463*0Sstevel@tonic-gate 
1464*0Sstevel@tonic-gate 	dlerrorack(dsp->ds_wq, mp, DL_SET_PHYS_ADDR_REQ, dl_err, err);
1465*0Sstevel@tonic-gate }
1466*0Sstevel@tonic-gate 
1467*0Sstevel@tonic-gate /*
1468*0Sstevel@tonic-gate  * DL_OK_ACK
1469*0Sstevel@tonic-gate  */
1470*0Sstevel@tonic-gate static void
1471*0Sstevel@tonic-gate proto_udqos_ack(dld_str_t *dsp, mblk_t *mp)
1472*0Sstevel@tonic-gate {
1473*0Sstevel@tonic-gate 	dlokack(dsp->ds_wq, mp, DL_UDQOS_REQ);
1474*0Sstevel@tonic-gate }
1475*0Sstevel@tonic-gate 
1476*0Sstevel@tonic-gate static void
1477*0Sstevel@tonic-gate proto_poll_disable(dld_str_t *dsp)
1478*0Sstevel@tonic-gate {
1479*0Sstevel@tonic-gate 	mac_handle_t	mh;
1480*0Sstevel@tonic-gate 
1481*0Sstevel@tonic-gate 	if (!dsp->ds_polling)
1482*0Sstevel@tonic-gate 		return;
1483*0Sstevel@tonic-gate 
1484*0Sstevel@tonic-gate 	/*
1485*0Sstevel@tonic-gate 	 * It should be impossible to enable raw mode if polling is turned on.
1486*0Sstevel@tonic-gate 	 */
1487*0Sstevel@tonic-gate 	ASSERT(dsp->ds_mode != DLD_RAW);
1488*0Sstevel@tonic-gate 
1489*0Sstevel@tonic-gate 	/*
1490*0Sstevel@tonic-gate 	 * Reset the resource_add callback.
1491*0Sstevel@tonic-gate 	 */
1492*0Sstevel@tonic-gate 	mh = dls_mac(dsp->ds_dc);
1493*0Sstevel@tonic-gate 	mac_resource_set(mh, NULL, NULL);
1494*0Sstevel@tonic-gate 
1495*0Sstevel@tonic-gate 	/*
1496*0Sstevel@tonic-gate 	 * Set receive function back to default.
1497*0Sstevel@tonic-gate 	 */
1498*0Sstevel@tonic-gate 	dls_rx_set(dsp->ds_dc, (dsp->ds_mode == DLD_FASTPATH) ?
1499*0Sstevel@tonic-gate 	    dld_str_rx_fastpath : dld_str_rx_unitdata, (void *)dsp);
1500*0Sstevel@tonic-gate 
1501*0Sstevel@tonic-gate 	/*
1502*0Sstevel@tonic-gate 	 * Note that polling is disabled.
1503*0Sstevel@tonic-gate 	 */
1504*0Sstevel@tonic-gate 	dsp->ds_polling = B_FALSE;
1505*0Sstevel@tonic-gate }
1506*0Sstevel@tonic-gate 
1507*0Sstevel@tonic-gate static boolean_t
1508*0Sstevel@tonic-gate proto_poll_enable(dld_str_t *dsp, dl_capab_poll_t *pollp)
1509*0Sstevel@tonic-gate {
1510*0Sstevel@tonic-gate 	mac_handle_t	mh;
1511*0Sstevel@tonic-gate 
1512*0Sstevel@tonic-gate 	ASSERT(!dsp->ds_polling);
1513*0Sstevel@tonic-gate 
1514*0Sstevel@tonic-gate 	/*
1515*0Sstevel@tonic-gate 	 * We cannot enable polling if raw mode
1516*0Sstevel@tonic-gate 	 * has been enabled.
1517*0Sstevel@tonic-gate 	 */
1518*0Sstevel@tonic-gate 	if (dsp->ds_mode == DLD_RAW)
1519*0Sstevel@tonic-gate 		return (B_FALSE);
1520*0Sstevel@tonic-gate 
1521*0Sstevel@tonic-gate 	mh = dls_mac(dsp->ds_dc);
1522*0Sstevel@tonic-gate 
1523*0Sstevel@tonic-gate 	/*
1524*0Sstevel@tonic-gate 	 * Register resources.
1525*0Sstevel@tonic-gate 	 */
1526*0Sstevel@tonic-gate 	mac_resource_set(mh, (mac_resource_add_t)pollp->poll_ring_add,
1527*0Sstevel@tonic-gate 	    (void *)pollp->poll_rx_handle);
1528*0Sstevel@tonic-gate 	mac_resources(mh);
1529*0Sstevel@tonic-gate 
1530*0Sstevel@tonic-gate 	/*
1531*0Sstevel@tonic-gate 	 * Set the receive function.
1532*0Sstevel@tonic-gate 	 */
1533*0Sstevel@tonic-gate 	dls_rx_set(dsp->ds_dc, (dls_rx_t)pollp->poll_rx,
1534*0Sstevel@tonic-gate 	    (void *)pollp->poll_rx_handle);
1535*0Sstevel@tonic-gate 
1536*0Sstevel@tonic-gate 	/*
1537*0Sstevel@tonic-gate 	 * Note that polling is enabled. This prevents further DLIOCHDRINFO
1538*0Sstevel@tonic-gate 	 * ioctls from overwriting the receive function pointer.
1539*0Sstevel@tonic-gate 	 */
1540*0Sstevel@tonic-gate 	dsp->ds_polling = B_TRUE;
1541*0Sstevel@tonic-gate 	return (B_TRUE);
1542*0Sstevel@tonic-gate }
1543*0Sstevel@tonic-gate 
1544*0Sstevel@tonic-gate /*
1545*0Sstevel@tonic-gate  * DL_CAPABILITY_ACK/DL_ERROR_ACK
1546*0Sstevel@tonic-gate  */
1547*0Sstevel@tonic-gate static void
1548*0Sstevel@tonic-gate proto_capability_ack(dld_str_t *dsp, mblk_t *mp)
1549*0Sstevel@tonic-gate {
1550*0Sstevel@tonic-gate 	dl_capability_ack_t	*dlap;
1551*0Sstevel@tonic-gate 	dl_capability_sub_t	*dlsp;
1552*0Sstevel@tonic-gate 	size_t			subsize;
1553*0Sstevel@tonic-gate 	dl_capab_poll_t		poll;
1554*0Sstevel@tonic-gate 	dl_capab_hcksum_t	hcksum;
1555*0Sstevel@tonic-gate 	dl_capab_zerocopy_t	zcopy;
1556*0Sstevel@tonic-gate 	uint8_t			*ptr;
1557*0Sstevel@tonic-gate 	uint32_t		cksum;
1558*0Sstevel@tonic-gate 	boolean_t		poll_cap;
1559*0Sstevel@tonic-gate 
1560*0Sstevel@tonic-gate 	/*
1561*0Sstevel@tonic-gate 	 * Initially assume no capabilities.
1562*0Sstevel@tonic-gate 	 */
1563*0Sstevel@tonic-gate 	subsize = 0;
1564*0Sstevel@tonic-gate 
1565*0Sstevel@tonic-gate 	/*
1566*0Sstevel@tonic-gate 	 * Check if polling can be enabled on this interface.
1567*0Sstevel@tonic-gate 	 * If advertising DL_CAPAB_POLL has not been explicitly disabled
1568*0Sstevel@tonic-gate 	 * then reserve space for that capability.
1569*0Sstevel@tonic-gate 	 */
1570*0Sstevel@tonic-gate 	poll_cap = ((dsp->ds_mip->mi_poll & DL_CAPAB_POLL) &&
1571*0Sstevel@tonic-gate 	    !(dld_opt & DLD_OPT_NO_POLL) && (dsp->ds_vid == VLAN_ID_NONE));
1572*0Sstevel@tonic-gate 	if (poll_cap) {
1573*0Sstevel@tonic-gate 		subsize += sizeof (dl_capability_sub_t) +
1574*0Sstevel@tonic-gate 		    sizeof (dl_capab_poll_t);
1575*0Sstevel@tonic-gate 	}
1576*0Sstevel@tonic-gate 
1577*0Sstevel@tonic-gate 	/*
1578*0Sstevel@tonic-gate 	 * If the MAC interface supports checksum offload then reserve
1579*0Sstevel@tonic-gate 	 * space for the DL_CAPAB_HCKSUM capability.
1580*0Sstevel@tonic-gate 	 */
1581*0Sstevel@tonic-gate 	if ((cksum = dsp->ds_mip->mi_cksum) != 0) {
1582*0Sstevel@tonic-gate 		subsize += sizeof (dl_capability_sub_t) +
1583*0Sstevel@tonic-gate 		    sizeof (dl_capab_hcksum_t);
1584*0Sstevel@tonic-gate 	}
1585*0Sstevel@tonic-gate 
1586*0Sstevel@tonic-gate 	/*
1587*0Sstevel@tonic-gate 	 * If DL_CAPAB_ZEROCOPY has not be explicitly disabled then
1588*0Sstevel@tonic-gate 	 * reserve space for it.
1589*0Sstevel@tonic-gate 	 */
1590*0Sstevel@tonic-gate 	if (!(dld_opt & DLD_OPT_NO_ZEROCOPY)) {
1591*0Sstevel@tonic-gate 		subsize += sizeof (dl_capability_sub_t) +
1592*0Sstevel@tonic-gate 		    sizeof (dl_capab_zerocopy_t);
1593*0Sstevel@tonic-gate 	}
1594*0Sstevel@tonic-gate 
1595*0Sstevel@tonic-gate 	/*
1596*0Sstevel@tonic-gate 	 * If there are no capabilities to advertise, send a DL_ERROR_ACK.
1597*0Sstevel@tonic-gate 	 */
1598*0Sstevel@tonic-gate 	if (subsize == 0) {
1599*0Sstevel@tonic-gate 		dlerrorack(dsp->ds_wq, mp, DL_CAPABILITY_REQ, DL_NOTSUPPORTED,
1600*0Sstevel@tonic-gate 		    0);
1601*0Sstevel@tonic-gate 		return;
1602*0Sstevel@tonic-gate 	}
1603*0Sstevel@tonic-gate 
1604*0Sstevel@tonic-gate 	if ((mp = mexchange(dsp->ds_wq, mp,
1605*0Sstevel@tonic-gate 	    sizeof (dl_capability_ack_t) + subsize, M_PROTO, 0)) == NULL)
1606*0Sstevel@tonic-gate 		return;
1607*0Sstevel@tonic-gate 
1608*0Sstevel@tonic-gate 	bzero(mp->b_rptr, sizeof (dl_capability_ack_t));
1609*0Sstevel@tonic-gate 	dlap = (dl_capability_ack_t *)mp->b_rptr;
1610*0Sstevel@tonic-gate 	dlap->dl_primitive = DL_CAPABILITY_ACK;
1611*0Sstevel@tonic-gate 	dlap->dl_sub_offset = sizeof (dl_capability_ack_t);
1612*0Sstevel@tonic-gate 	dlap->dl_sub_length = subsize;
1613*0Sstevel@tonic-gate 	ptr = (uint8_t *)&dlap[1];
1614*0Sstevel@tonic-gate 
1615*0Sstevel@tonic-gate 	/*
1616*0Sstevel@tonic-gate 	 * IP polling interface.
1617*0Sstevel@tonic-gate 	 */
1618*0Sstevel@tonic-gate 	if (poll_cap) {
1619*0Sstevel@tonic-gate 		/*
1620*0Sstevel@tonic-gate 		 * Attempt to disable just in case this is a re-negotiation.
1621*0Sstevel@tonic-gate 		 */
1622*0Sstevel@tonic-gate 		proto_poll_disable(dsp);
1623*0Sstevel@tonic-gate 
1624*0Sstevel@tonic-gate 		dlsp = (dl_capability_sub_t *)ptr;
1625*0Sstevel@tonic-gate 
1626*0Sstevel@tonic-gate 		dlsp->dl_cap = DL_CAPAB_POLL;
1627*0Sstevel@tonic-gate 		dlsp->dl_length = sizeof (dl_capab_poll_t);
1628*0Sstevel@tonic-gate 		ptr += sizeof (dl_capability_sub_t);
1629*0Sstevel@tonic-gate 
1630*0Sstevel@tonic-gate 		bzero(&poll, sizeof (dl_capab_poll_t));
1631*0Sstevel@tonic-gate 		poll.poll_version = POLL_VERSION_1;
1632*0Sstevel@tonic-gate 		poll.poll_flags = POLL_CAPABLE;
1633*0Sstevel@tonic-gate 		poll.poll_tx_handle = (uintptr_t)dsp->ds_dc;
1634*0Sstevel@tonic-gate 		poll.poll_tx = (uintptr_t)dls_tx;
1635*0Sstevel@tonic-gate 
1636*0Sstevel@tonic-gate 		dlcapabsetqid(&(poll.poll_mid), dsp->ds_rq);
1637*0Sstevel@tonic-gate 		bcopy(&poll, ptr, sizeof (dl_capab_poll_t));
1638*0Sstevel@tonic-gate 		ptr += sizeof (dl_capab_poll_t);
1639*0Sstevel@tonic-gate 	}
1640*0Sstevel@tonic-gate 
1641*0Sstevel@tonic-gate 	/*
1642*0Sstevel@tonic-gate 	 * TCP/IP checksum offload.
1643*0Sstevel@tonic-gate 	 */
1644*0Sstevel@tonic-gate 	if (cksum != 0) {
1645*0Sstevel@tonic-gate 		dlsp = (dl_capability_sub_t *)ptr;
1646*0Sstevel@tonic-gate 
1647*0Sstevel@tonic-gate 		dlsp->dl_cap = DL_CAPAB_HCKSUM;
1648*0Sstevel@tonic-gate 		dlsp->dl_length = sizeof (dl_capab_hcksum_t);
1649*0Sstevel@tonic-gate 		ptr += sizeof (dl_capability_sub_t);
1650*0Sstevel@tonic-gate 
1651*0Sstevel@tonic-gate 		bzero(&hcksum, sizeof (dl_capab_hcksum_t));
1652*0Sstevel@tonic-gate 		hcksum.hcksum_version = HCKSUM_VERSION_1;
1653*0Sstevel@tonic-gate 		hcksum.hcksum_txflags = cksum;
1654*0Sstevel@tonic-gate 
1655*0Sstevel@tonic-gate 		dlcapabsetqid(&(hcksum.hcksum_mid), dsp->ds_rq);
1656*0Sstevel@tonic-gate 		bcopy(&hcksum, ptr, sizeof (dl_capab_hcksum_t));
1657*0Sstevel@tonic-gate 		ptr += sizeof (dl_capab_hcksum_t);
1658*0Sstevel@tonic-gate 	}
1659*0Sstevel@tonic-gate 
1660*0Sstevel@tonic-gate 	/*
1661*0Sstevel@tonic-gate 	 * Zero copy
1662*0Sstevel@tonic-gate 	 */
1663*0Sstevel@tonic-gate 	if (!(dld_opt & DLD_OPT_NO_ZEROCOPY)) {
1664*0Sstevel@tonic-gate 		dlsp = (dl_capability_sub_t *)ptr;
1665*0Sstevel@tonic-gate 
1666*0Sstevel@tonic-gate 		dlsp->dl_cap = DL_CAPAB_ZEROCOPY;
1667*0Sstevel@tonic-gate 		dlsp->dl_length = sizeof (dl_capab_zerocopy_t);
1668*0Sstevel@tonic-gate 		ptr += sizeof (dl_capability_sub_t);
1669*0Sstevel@tonic-gate 
1670*0Sstevel@tonic-gate 		bzero(&zcopy, sizeof (dl_capab_zerocopy_t));
1671*0Sstevel@tonic-gate 		zcopy.zerocopy_version = ZEROCOPY_VERSION_1;
1672*0Sstevel@tonic-gate 		zcopy.zerocopy_flags = DL_CAPAB_VMSAFE_MEM;
1673*0Sstevel@tonic-gate 
1674*0Sstevel@tonic-gate 		dlcapabsetqid(&(zcopy.zerocopy_mid), dsp->ds_rq);
1675*0Sstevel@tonic-gate 		bcopy(&zcopy, ptr, sizeof (dl_capab_zerocopy_t));
1676*0Sstevel@tonic-gate 		ptr += sizeof (dl_capab_zerocopy_t);
1677*0Sstevel@tonic-gate 	}
1678*0Sstevel@tonic-gate 
1679*0Sstevel@tonic-gate 	ASSERT(ptr == mp->b_rptr + sizeof (dl_capability_ack_t) + subsize);
1680*0Sstevel@tonic-gate 	qreply(dsp->ds_wq, mp);
1681*0Sstevel@tonic-gate }
1682*0Sstevel@tonic-gate 
1683*0Sstevel@tonic-gate /*
1684*0Sstevel@tonic-gate  * DL_CAPABILITY_ACK/DL_ERROR_ACK
1685*0Sstevel@tonic-gate  */
1686*0Sstevel@tonic-gate static void
1687*0Sstevel@tonic-gate proto_capability_enable(dld_str_t *dsp, mblk_t *mp)
1688*0Sstevel@tonic-gate {
1689*0Sstevel@tonic-gate 	dl_capability_req_t	*dlp = (dl_capability_req_t *)mp->b_rptr;
1690*0Sstevel@tonic-gate 	dl_capability_sub_t	*sp;
1691*0Sstevel@tonic-gate 	size_t			size;
1692*0Sstevel@tonic-gate 	offset_t		off;
1693*0Sstevel@tonic-gate 	size_t			len;
1694*0Sstevel@tonic-gate 	offset_t		end;
1695*0Sstevel@tonic-gate 
1696*0Sstevel@tonic-gate 	dlp->dl_primitive = DL_CAPABILITY_ACK;
1697*0Sstevel@tonic-gate 
1698*0Sstevel@tonic-gate 	off = dlp->dl_sub_offset;
1699*0Sstevel@tonic-gate 	len = dlp->dl_sub_length;
1700*0Sstevel@tonic-gate 
1701*0Sstevel@tonic-gate 	/*
1702*0Sstevel@tonic-gate 	 * Walk the list of capabilities to be enabled.
1703*0Sstevel@tonic-gate 	 */
1704*0Sstevel@tonic-gate 	for (end = off + len; off < end; ) {
1705*0Sstevel@tonic-gate 		sp = (dl_capability_sub_t *)(mp->b_rptr + off);
1706*0Sstevel@tonic-gate 		size = sizeof (dl_capability_sub_t) + sp->dl_length;
1707*0Sstevel@tonic-gate 
1708*0Sstevel@tonic-gate 		if (off + size > end ||
1709*0Sstevel@tonic-gate 		    !IS_P2ALIGNED(off, sizeof (uint32_t))) {
1710*0Sstevel@tonic-gate 			dlerrorack(dsp->ds_wq, mp, DL_CAPABILITY_REQ,
1711*0Sstevel@tonic-gate 			    DL_BADPRIM, 0);
1712*0Sstevel@tonic-gate 			return;
1713*0Sstevel@tonic-gate 		}
1714*0Sstevel@tonic-gate 
1715*0Sstevel@tonic-gate 		switch (sp->dl_cap) {
1716*0Sstevel@tonic-gate 
1717*0Sstevel@tonic-gate 		/*
1718*0Sstevel@tonic-gate 		 * TCP/IP checksum offload to hardware.
1719*0Sstevel@tonic-gate 		 */
1720*0Sstevel@tonic-gate 		case DL_CAPAB_HCKSUM: {
1721*0Sstevel@tonic-gate 			dl_capab_hcksum_t 	*hcksump;
1722*0Sstevel@tonic-gate 			dl_capab_hcksum_t	hcksum;
1723*0Sstevel@tonic-gate 
1724*0Sstevel@tonic-gate 			ASSERT(dsp->ds_mip->mi_cksum != 0);
1725*0Sstevel@tonic-gate 
1726*0Sstevel@tonic-gate 			hcksump = (dl_capab_hcksum_t *)&sp[1];
1727*0Sstevel@tonic-gate 
1728*0Sstevel@tonic-gate 			/*
1729*0Sstevel@tonic-gate 			 * Copy for alignment.
1730*0Sstevel@tonic-gate 			 */
1731*0Sstevel@tonic-gate 			bcopy(hcksump, &hcksum, sizeof (dl_capab_hcksum_t));
1732*0Sstevel@tonic-gate 			dlcapabsetqid(&(hcksum.hcksum_mid), dsp->ds_rq);
1733*0Sstevel@tonic-gate 			bcopy(&hcksum, hcksump, sizeof (dl_capab_hcksum_t));
1734*0Sstevel@tonic-gate 			break;
1735*0Sstevel@tonic-gate 		}
1736*0Sstevel@tonic-gate 
1737*0Sstevel@tonic-gate 		/*
1738*0Sstevel@tonic-gate 		 * IP polling interface.
1739*0Sstevel@tonic-gate 		 */
1740*0Sstevel@tonic-gate 		case DL_CAPAB_POLL: {
1741*0Sstevel@tonic-gate 			dl_capab_poll_t 	*pollp;
1742*0Sstevel@tonic-gate 			dl_capab_poll_t		poll;
1743*0Sstevel@tonic-gate 
1744*0Sstevel@tonic-gate 			pollp = (dl_capab_poll_t *)&sp[1];
1745*0Sstevel@tonic-gate 
1746*0Sstevel@tonic-gate 			/*
1747*0Sstevel@tonic-gate 			 * Copy for alignment.
1748*0Sstevel@tonic-gate 			 */
1749*0Sstevel@tonic-gate 			bcopy(pollp, &poll, sizeof (dl_capab_poll_t));
1750*0Sstevel@tonic-gate 
1751*0Sstevel@tonic-gate 			switch (poll.poll_flags) {
1752*0Sstevel@tonic-gate 			default:
1753*0Sstevel@tonic-gate 				/*FALLTHRU*/
1754*0Sstevel@tonic-gate 			case POLL_DISABLE:
1755*0Sstevel@tonic-gate 				proto_poll_disable(dsp);
1756*0Sstevel@tonic-gate 				break;
1757*0Sstevel@tonic-gate 
1758*0Sstevel@tonic-gate 			case POLL_ENABLE:
1759*0Sstevel@tonic-gate 				ASSERT(!(dld_opt & DLD_OPT_NO_POLL));
1760*0Sstevel@tonic-gate 
1761*0Sstevel@tonic-gate 				/*
1762*0Sstevel@tonic-gate 				 * Make sure polling is disabled.
1763*0Sstevel@tonic-gate 				 */
1764*0Sstevel@tonic-gate 				proto_poll_disable(dsp);
1765*0Sstevel@tonic-gate 
1766*0Sstevel@tonic-gate 				/*
1767*0Sstevel@tonic-gate 				 * Now attempt enable it.
1768*0Sstevel@tonic-gate 				 */
1769*0Sstevel@tonic-gate 				if (!proto_poll_enable(dsp, &poll))
1770*0Sstevel@tonic-gate 					break;
1771*0Sstevel@tonic-gate 
1772*0Sstevel@tonic-gate 				bzero(&poll, sizeof (dl_capab_poll_t));
1773*0Sstevel@tonic-gate 				poll.poll_flags = POLL_ENABLE;
1774*0Sstevel@tonic-gate 				break;
1775*0Sstevel@tonic-gate 			}
1776*0Sstevel@tonic-gate 
1777*0Sstevel@tonic-gate 			dlcapabsetqid(&(poll.poll_mid), dsp->ds_rq);
1778*0Sstevel@tonic-gate 			bcopy(&poll, pollp, sizeof (dl_capab_poll_t));
1779*0Sstevel@tonic-gate 			break;
1780*0Sstevel@tonic-gate 		}
1781*0Sstevel@tonic-gate 		default:
1782*0Sstevel@tonic-gate 			break;
1783*0Sstevel@tonic-gate 		}
1784*0Sstevel@tonic-gate 
1785*0Sstevel@tonic-gate 		off += size;
1786*0Sstevel@tonic-gate 	}
1787*0Sstevel@tonic-gate 
1788*0Sstevel@tonic-gate 	qreply(dsp->ds_wq, mp);
1789*0Sstevel@tonic-gate }
1790*0Sstevel@tonic-gate 
1791*0Sstevel@tonic-gate /*
1792*0Sstevel@tonic-gate  * DL_NOTIFY_ACK
1793*0Sstevel@tonic-gate  */
1794*0Sstevel@tonic-gate static void
1795*0Sstevel@tonic-gate proto_notify_ack(dld_str_t *dsp, mblk_t *mp, uint_t enable_set, uint_t ack_set)
1796*0Sstevel@tonic-gate {
1797*0Sstevel@tonic-gate 	/*
1798*0Sstevel@tonic-gate 	 * Cache the notifications that are being enabled.
1799*0Sstevel@tonic-gate 	 */
1800*0Sstevel@tonic-gate 	dsp->ds_notifications = enable_set;
1801*0Sstevel@tonic-gate 
1802*0Sstevel@tonic-gate 	/*
1803*0Sstevel@tonic-gate 	 * The ACK carries all notifications regardless of which set is
1804*0Sstevel@tonic-gate 	 * being enabled.
1805*0Sstevel@tonic-gate 	 */
1806*0Sstevel@tonic-gate 	dlnotifyack(dsp->ds_wq, mp, ack_set);
1807*0Sstevel@tonic-gate 
1808*0Sstevel@tonic-gate 	/*
1809*0Sstevel@tonic-gate 	 * Solicit DL_NOTIFY_IND messages for each enabled notification.
1810*0Sstevel@tonic-gate 	 */
1811*0Sstevel@tonic-gate 	if (dsp->ds_notifications != 0)
1812*0Sstevel@tonic-gate 		dld_str_notify_ind(dsp);
1813*0Sstevel@tonic-gate }
1814