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