xref: /illumos-gate/usr/src/uts/common/io/dld/dld_proto.c (revision 1160694128cd3980cc06abe31af529a887efd310)
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, (dsp->ds_mode == DLD_RAW) ?
482 	    dld_str_rx_raw : dld_str_rx_unitdata, dsp);
483 
484 	/*
485 	 * Set the M_DATA handler.
486 	 */
487 	if (dsp->ds_mode == DLD_RAW)
488 		dld_str_tx_raw(dsp);
489 
490 	/*
491 	 * Bind the channel such that it can receive packets.
492 	 */
493 	dsp->ds_sap = dlp->dl_sap;
494 	err = dls_bind(dsp->ds_dc, dlp->dl_sap);
495 
496 	proto_bind_ack(dsp, mp, err);
497 	return (err == 0);
498 }
499 
500 /*
501  * DL_UNBIND_REQ
502  */
503 /*ARGSUSED*/
504 static boolean_t
505 proto_unbind_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp)
506 {
507 	ASSERT(PERIM_EXCL(dsp->ds_wq));
508 
509 	if (dsp->ds_dlstate != DL_IDLE) {
510 		dlerrorack(dsp->ds_wq, mp, DL_UNBIND_REQ, DL_OUTSTATE, 0);
511 		return (B_FALSE);
512 	}
513 
514 	if (MBLKL(mp) < sizeof (dl_unbind_req_t)) {
515 		dlerrorack(dsp->ds_wq, mp, DL_BIND_REQ, DL_BADPRIM, 0);
516 		return (B_FALSE);
517 	}
518 
519 	dsp->ds_dlstate = DL_UNBIND_PENDING;
520 
521 	/*
522 	 * Flush any remaining packets scheduled for transmission.
523 	 */
524 	flushq(dsp->ds_wq, FLUSHALL);
525 
526 	/*
527 	 * Reset the M_DATA handler.
528 	 */
529 	dld_str_tx_drop(dsp);
530 
531 	/*
532 	 * Unbind the channel to stop packets being received.
533 	 */
534 	dls_unbind(dsp->ds_dc);
535 
536 	/*
537 	 * Disable polling mode, if it is enabled.
538 	 */
539 	proto_poll_disable(dsp);
540 
541 	/*
542 	 * Clear the receive callback.
543 	 */
544 	dls_rx_set(dsp->ds_dc, NULL, NULL);
545 
546 	/*
547 	 * Set the mode back to the default (unitdata).
548 	 */
549 	dsp->ds_mode = DLD_UNITDATA;
550 
551 	proto_unbind_ack(dsp, mp);
552 	return (B_TRUE);
553 }
554 
555 /*
556  * DL_PROMISCON_REQ
557  */
558 static boolean_t
559 proto_promiscon_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp)
560 {
561 	dl_promiscon_req_t	*dlp = (dl_promiscon_req_t *)udlp;
562 	int			err;
563 
564 	ASSERT(PERIM_EXCL(dsp->ds_wq));
565 
566 	if (dsp->ds_dlstate == DL_UNATTACHED ||
567 	    DL_ACK_PENDING(dsp->ds_dlstate)) {
568 		dlerrorack(dsp->ds_wq, mp, DL_PROMISCON_REQ, DL_OUTSTATE, 0);
569 		return (B_FALSE);
570 	}
571 
572 	if (MBLKL(mp) < sizeof (dl_promiscon_req_t)) {
573 		dlerrorack(dsp->ds_wq, mp, DL_PROMISCON_REQ, DL_BADPRIM, 0);
574 		return (B_FALSE);
575 	}
576 
577 	switch (dlp->dl_level) {
578 	case DL_PROMISC_SAP:
579 		dsp->ds_promisc |= DLS_PROMISC_SAP;
580 		break;
581 
582 	case DL_PROMISC_MULTI:
583 		dsp->ds_promisc |= DLS_PROMISC_MULTI;
584 		break;
585 
586 	case DL_PROMISC_PHYS:
587 		dsp->ds_promisc |= DLS_PROMISC_PHYS;
588 		break;
589 
590 	default:
591 		dlerrorack(dsp->ds_wq, mp, DL_PROMISCON_REQ, DL_NOTSUPPORTED,
592 		    0);
593 		return (B_FALSE);
594 	}
595 
596 	/*
597 	 * Adjust channel promiscuity.
598 	 */
599 	err = dls_promisc(dsp->ds_dc, dsp->ds_promisc);
600 	proto_promiscon_ack(dsp, mp, err);
601 	return (err == 0);
602 }
603 
604 /*
605  * DL_PROMISCOFF_REQ
606  */
607 static boolean_t
608 proto_promiscoff_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp)
609 {
610 	dl_promiscoff_req_t	*dlp = (dl_promiscoff_req_t *)udlp;
611 	int			err;
612 
613 	ASSERT(PERIM_EXCL(dsp->ds_wq));
614 
615 	if (dsp->ds_dlstate == DL_UNATTACHED ||
616 	    DL_ACK_PENDING(dsp->ds_dlstate)) {
617 		dlerrorack(dsp->ds_wq, mp, DL_PROMISCOFF_REQ, DL_OUTSTATE, 0);
618 		return (B_FALSE);
619 	}
620 
621 	if (MBLKL(mp) < sizeof (dl_promiscoff_req_t)) {
622 		dlerrorack(dsp->ds_wq, mp, DL_PROMISCOFF_REQ, DL_BADPRIM, 0);
623 		return (B_FALSE);
624 	}
625 
626 	switch (dlp->dl_level) {
627 	case DL_PROMISC_SAP:
628 		if (!(dsp->ds_promisc & DLS_PROMISC_SAP))
629 			goto notenab;
630 
631 		dsp->ds_promisc &= ~DLS_PROMISC_SAP;
632 		break;
633 
634 	case DL_PROMISC_MULTI:
635 		if (!(dsp->ds_promisc & DLS_PROMISC_MULTI))
636 			goto notenab;
637 
638 		dsp->ds_promisc &= ~DLS_PROMISC_MULTI;
639 		break;
640 
641 	case DL_PROMISC_PHYS:
642 		if (!(dsp->ds_promisc & DLS_PROMISC_PHYS))
643 			goto notenab;
644 
645 		dsp->ds_promisc &= ~DLS_PROMISC_PHYS;
646 		break;
647 
648 	default:
649 		dlerrorack(dsp->ds_wq, mp, DL_PROMISCOFF_REQ, DL_NOTSUPPORTED,
650 		    0);
651 		return (B_FALSE);
652 	}
653 
654 	/*
655 	 * Adjust channel promiscuity.
656 	 */
657 	err = dls_promisc(dsp->ds_dc, dsp->ds_promisc);
658 
659 	proto_promiscoff_ack(dsp, mp, err);
660 	return (err == 0);
661 
662 notenab:
663 	dlerrorack(dsp->ds_wq, mp, DL_PROMISCOFF_REQ, DL_NOTENAB, 0);
664 	return (B_FALSE);
665 }
666 
667 /*
668  * DL_ENABMULTI_REQ
669  */
670 static boolean_t
671 proto_enabmulti_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp)
672 {
673 	dl_enabmulti_req_t	*dlp = (dl_enabmulti_req_t *)udlp;
674 	int			err;
675 
676 	ASSERT(PERIM_EXCL(dsp->ds_wq));
677 
678 	if (dsp->ds_dlstate == DL_UNATTACHED ||
679 	    DL_ACK_PENDING(dsp->ds_dlstate)) {
680 		dlerrorack(dsp->ds_wq, mp, DL_ENABMULTI_REQ, DL_OUTSTATE, 0);
681 		return (B_FALSE);
682 	}
683 
684 	if (MBLKL(mp) < sizeof (dl_enabmulti_req_t) ||
685 	    !MBLKIN(mp, dlp->dl_addr_offset, dlp->dl_addr_length) ||
686 	    dlp->dl_addr_length != dsp->ds_mip->mi_addr_length) {
687 		dlerrorack(dsp->ds_wq, mp, DL_ENABMULTI_REQ, DL_BADPRIM, 0);
688 		return (B_FALSE);
689 	}
690 
691 	err = dls_multicst_add(dsp->ds_dc, mp->b_rptr + dlp->dl_addr_offset);
692 	proto_enabmulti_ack(dsp, mp, err);
693 	return (err == 0);
694 }
695 
696 /*
697  * DL_DISABMULTI_REQ
698  */
699 static boolean_t
700 proto_disabmulti_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp)
701 {
702 	dl_disabmulti_req_t	*dlp = (dl_disabmulti_req_t *)udlp;
703 	int			err;
704 
705 	ASSERT(PERIM_EXCL(dsp->ds_wq));
706 
707 	if (dsp->ds_dlstate == DL_UNATTACHED ||
708 	    DL_ACK_PENDING(dsp->ds_dlstate)) {
709 		dlerrorack(dsp->ds_wq, mp, DL_DISABMULTI_REQ, DL_OUTSTATE, 0);
710 		return (B_FALSE);
711 	}
712 
713 	if (MBLKL(mp) < sizeof (dl_disabmulti_req_t) ||
714 	    !MBLKIN(mp, dlp->dl_addr_offset, dlp->dl_addr_length) ||
715 	    dlp->dl_addr_length != dsp->ds_mip->mi_addr_length) {
716 		dlerrorack(dsp->ds_wq, mp, DL_DISABMULTI_REQ, DL_BADPRIM, 0);
717 		return (B_FALSE);
718 	}
719 
720 	err = dls_multicst_remove(dsp->ds_dc, mp->b_rptr + dlp->dl_addr_offset);
721 	proto_disabmulti_ack(dsp, mp, err);
722 	return (err == 0);
723 }
724 
725 /*
726  * DL_PHYS_ADDR_REQ
727  */
728 static boolean_t
729 proto_physaddr_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp)
730 {
731 	dl_phys_addr_req_t	*dlp = (dl_phys_addr_req_t *)udlp;
732 
733 	if (dsp->ds_dlstate == DL_UNATTACHED ||
734 	    DL_ACK_PENDING(dsp->ds_dlstate)) {
735 		dlerrorack(dsp->ds_wq, mp, DL_PHYS_ADDR_REQ, DL_OUTSTATE, 0);
736 		return (B_FALSE);
737 	}
738 
739 	if (MBLKL(mp) < sizeof (dl_phys_addr_req_t)) {
740 		dlerrorack(dsp->ds_wq, mp, DL_PHYS_ADDR_REQ, DL_BADPRIM, 0);
741 		return (B_FALSE);
742 	}
743 
744 	if (dlp->dl_addr_type != DL_CURR_PHYS_ADDR &&
745 	    dlp->dl_addr_type != DL_FACT_PHYS_ADDR) {
746 		dlerrorack(dsp->ds_wq, mp, DL_PHYS_ADDR_REQ, DL_UNSUPPORTED, 0);
747 		return (B_FALSE);
748 	}
749 
750 	proto_physaddr_ack(dsp, mp, dlp->dl_addr_type);
751 	return (B_TRUE);
752 }
753 
754 /*
755  * DL_SET_PHYS_ADDR_REQ
756  */
757 static boolean_t
758 proto_setphysaddr_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp)
759 {
760 	dl_set_phys_addr_req_t	*dlp = (dl_set_phys_addr_req_t *)udlp;
761 	int			err;
762 
763 	ASSERT(PERIM_EXCL(dsp->ds_wq));
764 
765 	if (dsp->ds_dlstate == DL_UNATTACHED ||
766 	    DL_ACK_PENDING(dsp->ds_dlstate)) {
767 		dlerrorack(dsp->ds_wq, mp, DL_SET_PHYS_ADDR_REQ, DL_OUTSTATE,
768 		    0);
769 		return (B_FALSE);
770 	}
771 
772 	if (MBLKL(mp) < sizeof (dl_set_phys_addr_req_t) ||
773 	    !MBLKIN(mp, dlp->dl_addr_offset, dlp->dl_addr_length) ||
774 	    dlp->dl_addr_length != dsp->ds_mip->mi_addr_length) {
775 		dlerrorack(dsp->ds_wq, mp, DL_SET_PHYS_ADDR_REQ, DL_BADPRIM,
776 		    0);
777 		return (B_FALSE);
778 	}
779 
780 	err = mac_unicst_set(dsp->ds_mh, mp->b_rptr + dlp->dl_addr_offset);
781 	proto_setphysaddr_ack(dsp, mp, err);
782 	return (err == 0);
783 }
784 
785 /*
786  * DL_UDQOS_REQ
787  */
788 static boolean_t
789 proto_udqos_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp)
790 {
791 	dl_udqos_req_t		*dlp = (dl_udqos_req_t *)udlp;
792 	dl_qos_cl_sel1_t	*selp;
793 	int			off, len;
794 
795 	ASSERT(PERIM_EXCL(dsp->ds_wq));
796 
797 	off = dlp->dl_qos_offset;
798 	len = dlp->dl_qos_length;
799 
800 	if (MBLKL(mp) < sizeof (dl_udqos_req_t) || !MBLKIN(mp, off, len)) {
801 		dlerrorack(dsp->ds_wq, mp, DL_UDQOS_REQ, DL_BADPRIM, 0);
802 		return (B_FALSE);
803 	}
804 
805 	selp = (dl_qos_cl_sel1_t *)(mp->b_rptr + off);
806 	if (selp->dl_qos_type != DL_QOS_CL_SEL1) {
807 		dlerrorack(dsp->ds_wq, mp, DL_UDQOS_REQ, DL_BADQOSTYPE, 0);
808 		return (B_FALSE);
809 	}
810 
811 	if (dsp->ds_vid == VLAN_ID_NONE ||
812 	    selp->dl_priority > (1 << VLAN_PRI_SIZE) - 1 ||
813 	    selp->dl_priority < 0) {
814 		dlerrorack(dsp->ds_wq, mp, DL_UDQOS_REQ, DL_BADQOSPARAM, 0);
815 		return (B_FALSE);
816 	}
817 
818 	dsp->ds_pri = selp->dl_priority;
819 	proto_udqos_ack(dsp, mp);
820 	return (B_TRUE);
821 }
822 
823 /*
824  * DL_CAPABILITY_REQ
825  */
826 /*ARGSUSED*/
827 static boolean_t
828 proto_capability_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp)
829 {
830 	dl_capability_req_t	*dlp = (dl_capability_req_t *)udlp;
831 
832 	if (dsp->ds_dlstate == DL_UNATTACHED ||
833 	    DL_ACK_PENDING(dsp->ds_dlstate)) {
834 		dlerrorack(dsp->ds_wq, mp, DL_CAPABILITY_REQ, DL_OUTSTATE,
835 		    0);
836 		return (B_FALSE);
837 	}
838 
839 	if (MBLKL(mp) < sizeof (dl_capability_req_t)) {
840 		dlerrorack(dsp->ds_wq, mp, DL_CAPABILITY_REQ, DL_BADPRIM, 0);
841 		return (B_FALSE);
842 	}
843 
844 	/*
845 	 * This request is overloaded. If there are no requested capabilities
846 	 * then we just want to acknowledge with all the capabilities we
847 	 * support. Otherwise we enable the set of capabilities requested.
848 	 */
849 	if (dlp->dl_sub_length == 0) {
850 		proto_capability_ack(dsp, mp);
851 		return (B_TRUE);
852 	}
853 
854 	if (!MBLKIN(mp, dlp->dl_sub_offset, dlp->dl_sub_length)) {
855 		dlerrorack(dsp->ds_wq, mp, DL_CAPABILITY_REQ, DL_BADPRIM, 0);
856 		return (B_FALSE);
857 	}
858 
859 	proto_capability_enable(dsp, mp);
860 	return (B_TRUE);
861 }
862 
863 /*
864  * DL_NOTIFY_REQ
865  */
866 static boolean_t
867 proto_notify_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp)
868 {
869 	dl_notify_req_t		*dlp = (dl_notify_req_t *)udlp;
870 	uint_t			notifications =
871 	    DL_NOTE_PROMISC_ON_PHYS |
872 	    DL_NOTE_PROMISC_OFF_PHYS |
873 	    DL_NOTE_PHYS_ADDR |
874 	    DL_NOTE_LINK_UP |
875 	    DL_NOTE_LINK_DOWN |
876 	    DL_NOTE_CAPAB_RENEG;
877 
878 	if (dsp->ds_dlstate == DL_UNATTACHED ||
879 	    DL_ACK_PENDING(dsp->ds_dlstate)) {
880 		dlerrorack(dsp->ds_wq, mp, DL_NOTIFY_REQ, DL_OUTSTATE,
881 		    0);
882 		return (B_FALSE);
883 	}
884 
885 	if (MBLKL(mp) < sizeof (dl_notify_req_t)) {
886 		dlerrorack(dsp->ds_wq, mp, DL_NOTIFY_REQ, DL_BADPRIM, 0);
887 		return (B_FALSE);
888 	}
889 
890 	if (dsp->ds_mip->mi_stat[MAC_STAT_IFSPEED])
891 		notifications |= DL_NOTE_SPEED;
892 
893 	proto_notify_ack(dsp, mp, dlp->dl_notifications & notifications,
894 	    notifications);
895 	return (B_TRUE);
896 }
897 
898 /*
899  * DL_UINTDATA_REQ
900  */
901 static boolean_t
902 proto_unitdata_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp)
903 {
904 	queue_t			*q = dsp->ds_wq;
905 	dl_unitdata_req_t	*dlp = (dl_unitdata_req_t *)udlp;
906 	off_t			off;
907 	size_t			len;
908 	size_t			size;
909 	const uint8_t		*addr;
910 	uint16_t		sap;
911 	uint_t			addr_length;
912 	mblk_t			*bp;
913 	mblk_t			*cont;
914 	uint32_t		start;
915 	uint32_t		stuff;
916 	uint32_t		end;
917 	uint32_t		value;
918 	uint32_t		flags;
919 
920 	if (dsp->ds_dlstate != DL_IDLE) {
921 		dlerrorack(q, mp, DL_UNITDATA_REQ, DL_OUTSTATE, 0);
922 		return (B_FALSE);
923 	}
924 
925 	if (MBLKL(mp) < sizeof (dl_unitdata_req_t) || mp->b_cont == NULL) {
926 		dlerrorack(q, mp, DL_UNITDATA_REQ, DL_BADPRIM, 0);
927 		return (B_FALSE);
928 	}
929 
930 	off = dlp->dl_dest_addr_offset;
931 	len = dlp->dl_dest_addr_length;
932 
933 	if (!MBLKIN(mp, off, len) || !IS_P2ALIGNED(off, sizeof (uint16_t))) {
934 		dlerrorack(q, mp, DL_UNITDATA_REQ, DL_BADPRIM, 0);
935 		return (B_FALSE);
936 	}
937 
938 	addr_length = dsp->ds_mip->mi_addr_length;
939 	if (len != addr_length + sizeof (uint16_t))
940 		goto badaddr;
941 
942 	addr = mp->b_rptr + off;
943 	sap = *(uint16_t *)(mp->b_rptr + off + addr_length);
944 
945 	/*
946 	 * Check the length of the packet and the block types.
947 	 */
948 	size = 0;
949 	cont = mp->b_cont;
950 	for (bp = cont; bp != NULL; bp = bp->b_cont) {
951 		if (DB_TYPE(bp) != M_DATA)
952 			goto baddata;
953 
954 		size += MBLKL(bp);
955 	}
956 
957 	if (size > dsp->ds_mip->mi_sdu_max)
958 		goto baddata;
959 
960 	/*
961 	 * Build a packet header.
962 	 */
963 	if ((bp = dls_header(dsp->ds_dc, addr, sap, dsp->ds_pri)) == NULL)
964 		goto badaddr;
965 
966 	/*
967 	 * We no longer need the M_PROTO header, so free it.
968 	 */
969 	freeb(mp);
970 
971 	/*
972 	 * Transfer the checksum offload information if it is present.
973 	 */
974 	hcksum_retrieve(cont, NULL, NULL, &start, &stuff, &end, &value,
975 	    &flags);
976 	(void) hcksum_assoc(bp, NULL, NULL, start, stuff, end, value, flags,
977 	    0);
978 
979 	/*
980 	 * Link the payload onto the new header.
981 	 */
982 	ASSERT(bp->b_cont == NULL);
983 	bp->b_cont = cont;
984 
985 	/*
986 	 * If something is already queued then we must queue to avoid
987 	 * re-ordering.
988 	 */
989 	if (q->q_first != NULL) {
990 		(void) putq(q, bp);
991 		return (B_TRUE);
992 	}
993 
994 	/*
995 	 * Attempt to transmit the packet.
996 	 */
997 	if ((mp = dls_tx(dsp->ds_dc, bp)) != NULL) {
998 		noenable(q);
999 		while ((bp = mp) != NULL) {
1000 			mp = mp->b_next;
1001 			bp->b_next = NULL;
1002 			(void) putq(q, bp);
1003 		}
1004 	}
1005 	return (B_TRUE);
1006 
1007 badaddr:
1008 	dlerrorack(q, mp, DL_UNITDATA_REQ, DL_BADADDR, 0);
1009 	return (B_FALSE);
1010 
1011 baddata:
1012 	dluderrorind(q, mp, (void *)addr, len, DL_BADDATA, 0);
1013 	return (B_FALSE);
1014 }
1015 
1016 /*
1017  * DL_PASSIVE_REQ
1018  */
1019 /* ARGSUSED */
1020 static boolean_t
1021 proto_passive_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp)
1022 {
1023 	ASSERT(PERIM_EXCL(dsp->ds_wq));
1024 
1025 	/*
1026 	 * If we've already become active by issuing an active primitive,
1027 	 * then it's too late to try to become passive.
1028 	 */
1029 	if (dsp->ds_passivestate == DLD_ACTIVE) {
1030 		dlerrorack(dsp->ds_wq, mp, DL_PASSIVE_REQ, DL_OUTSTATE, 0);
1031 		return (B_FALSE);
1032 	}
1033 
1034 	if (MBLKL(mp) < sizeof (dl_passive_req_t)) {
1035 		dlerrorack(dsp->ds_wq, mp, DL_PASSIVE_REQ, DL_BADPRIM, 0);
1036 		return (B_FALSE);
1037 	}
1038 
1039 	dsp->ds_passivestate = DLD_PASSIVE;
1040 	dlokack(dsp->ds_wq, mp, DL_PASSIVE_REQ);
1041 	return (B_TRUE);
1042 }
1043 
1044 /*
1045  * Catch-all handler.
1046  */
1047 static boolean_t
1048 proto_req(dld_str_t *dsp, union DL_primitives *dlp, mblk_t *mp)
1049 {
1050 	dlerrorack(dsp->ds_wq, mp, dlp->dl_primitive, DL_UNSUPPORTED, 0);
1051 	return (B_FALSE);
1052 }
1053 
1054 typedef struct dl_info_ack_wrapper {
1055 	dl_info_ack_t		dl_info;
1056 	uint8_t			dl_addr[MAXADDRLEN + sizeof (uint16_t)];
1057 	uint8_t			dl_brdcst_addr[MAXADDRLEN];
1058 	dl_qos_cl_range1_t	dl_qos_range1;
1059 	dl_qos_cl_sel1_t	dl_qos_sel1;
1060 } dl_info_ack_wrapper_t;
1061 
1062 #define	NEG(x)	-(x)
1063 
1064 /*
1065  * DL_INFO_ACK
1066  */
1067 static void
1068 proto_info_ack(dld_str_t *dsp, mblk_t *mp)
1069 {
1070 	dl_info_ack_wrapper_t	*dlwp;
1071 	dl_info_ack_t		*dlp;
1072 	dl_qos_cl_sel1_t	*selp;
1073 	dl_qos_cl_range1_t	*rangep;
1074 	uint8_t			*addr;
1075 	uint8_t			*brdcst_addr;
1076 	dld_node_t		*dnp;
1077 	uint_t			addr_length;
1078 	uint_t			sap_length;
1079 
1080 	/*
1081 	 * Swap the request message for one large enough to contain the
1082 	 * wrapper structure defined above.
1083 	 */
1084 	if ((mp = mexchange(dsp->ds_wq, mp, sizeof (dl_info_ack_wrapper_t),
1085 	    M_PCPROTO, 0)) == NULL)
1086 		return;
1087 
1088 	bzero(mp->b_rptr, sizeof (dl_info_ack_wrapper_t));
1089 	dlwp = (dl_info_ack_wrapper_t *)mp->b_rptr;
1090 
1091 	dlp = &(dlwp->dl_info);
1092 	ASSERT(dlp == (dl_info_ack_t *)mp->b_rptr);
1093 
1094 	dlp->dl_primitive = DL_INFO_ACK;
1095 
1096 	/*
1097 	 * Set up the sub-structure pointers.
1098 	 */
1099 	addr = dlwp->dl_addr;
1100 	brdcst_addr = dlwp->dl_brdcst_addr;
1101 	rangep = &(dlwp->dl_qos_range1);
1102 	selp = &(dlwp->dl_qos_sel1);
1103 
1104 	/*
1105 	 * This driver supports only version 2 connectionless DLPI provider
1106 	 * nodes.
1107 	 */
1108 	dlp->dl_service_mode = DL_CLDLS;
1109 	dlp->dl_version = DL_VERSION_2;
1110 
1111 	/*
1112 	 * Set the style of the provider from the dld_node_t structure
1113 	 * representing the dev_t that was opened.
1114 	 */
1115 	dnp = dsp->ds_dnp;
1116 	dlp->dl_provider_style = dnp->dn_style;
1117 	ASSERT(dlp->dl_provider_style == DL_STYLE1 ||
1118 	    dlp->dl_provider_style == DL_STYLE2);
1119 
1120 	/*
1121 	 * Set the current DLPI state.
1122 	 */
1123 	dlp->dl_current_state = dsp->ds_dlstate;
1124 
1125 	/*
1126 	 * Gratuitously set the media type. This is because the Cisco VPN 3000
1127 	 * module assumes that the media type is known prior to DL_ATTACH_REQ
1128 	 * being completed.
1129 	 */
1130 	dlp->dl_mac_type = DL_ETHER;
1131 
1132 	/*
1133 	 * If the stream is not at least attached then we're done.
1134 	 */
1135 	if (dsp->ds_dlstate == DL_UNATTACHED ||
1136 	    dsp->ds_dlstate == DL_ATTACH_PENDING ||
1137 	    dsp->ds_dlstate == DL_DETACH_PENDING)
1138 		goto done;
1139 
1140 	/*
1141 	 * Set the media type (properly this time).
1142 	 */
1143 	dlp->dl_mac_type = dsp->ds_mip->mi_media;
1144 
1145 	/*
1146 	 * Set the DLSAP length. We only support 16 bit values and they
1147 	 * appear after the MAC address portion of DLSAP addresses.
1148 	 */
1149 	sap_length = sizeof (uint16_t);
1150 	dlp->dl_sap_length = NEG(sap_length);
1151 
1152 	/*
1153 	 * Set the minimum and maximum payload sizes.
1154 	 */
1155 	dlp->dl_min_sdu = dsp->ds_mip->mi_sdu_min;
1156 	dlp->dl_max_sdu = dsp->ds_mip->mi_sdu_max;
1157 
1158 	addr_length = dsp->ds_mip->mi_addr_length;
1159 	ASSERT(addr_length != 0);
1160 
1161 	/*
1162 	 * Copy in the media broadcast address.
1163 	 */
1164 	dlp->dl_brdcst_addr_offset = (uintptr_t)brdcst_addr - (uintptr_t)dlp;
1165 	bcopy(dsp->ds_mip->mi_brdcst_addr, brdcst_addr, addr_length);
1166 	dlp->dl_brdcst_addr_length = addr_length;
1167 
1168 	/*
1169 	 * We only support QoS information for VLAN interfaces.
1170 	 */
1171 	if (dsp->ds_vid != VLAN_ID_NONE) {
1172 		dlp->dl_qos_range_offset = (uintptr_t)rangep - (uintptr_t)dlp;
1173 		dlp->dl_qos_range_length = sizeof (dl_qos_cl_range1_t);
1174 
1175 		rangep->dl_qos_type = DL_QOS_CL_RANGE1;
1176 		rangep->dl_trans_delay.dl_target_value = DL_UNKNOWN;
1177 		rangep->dl_trans_delay.dl_accept_value = DL_UNKNOWN;
1178 		rangep->dl_protection.dl_min = DL_UNKNOWN;
1179 		rangep->dl_protection.dl_max = DL_UNKNOWN;
1180 		rangep->dl_residual_error = DL_UNKNOWN;
1181 
1182 		/*
1183 		 * Specify the supported range of priorities.
1184 		 */
1185 		rangep->dl_priority.dl_min = 0;
1186 		rangep->dl_priority.dl_max = (1 << VLAN_PRI_SIZE) - 1;
1187 
1188 		dlp->dl_qos_offset = (uintptr_t)selp - (uintptr_t)dlp;
1189 		dlp->dl_qos_length = sizeof (dl_qos_cl_sel1_t);
1190 
1191 		selp->dl_qos_type = DL_QOS_CL_SEL1;
1192 		selp->dl_trans_delay = DL_UNKNOWN;
1193 		selp->dl_protection = DL_UNKNOWN;
1194 		selp->dl_residual_error = DL_UNKNOWN;
1195 
1196 		/*
1197 		 * Specify the current priority (which can be changed by
1198 		 * the DL_UDQOS_REQ primitive).
1199 		 */
1200 		selp->dl_priority = dsp->ds_pri;
1201 	} else {
1202 		/*
1203 		 * Shorten the buffer to lose the unused QoS information
1204 		 * structures. This is to work around a bug in the Cisco VPN
1205 		 * 3000 module.
1206 		 */
1207 		mp->b_wptr = (uint8_t *)rangep;
1208 	}
1209 
1210 	dlp->dl_addr_length = addr_length + sizeof (uint16_t);
1211 	if (dsp->ds_dlstate == DL_IDLE) {
1212 		/*
1213 		 * The stream is bound. Therefore we can formulate a valid
1214 		 * DLSAP address.
1215 		 */
1216 		dlp->dl_addr_offset = (uintptr_t)addr - (uintptr_t)dlp;
1217 		bcopy(dsp->ds_curr_addr, addr, addr_length);
1218 		*(uint16_t *)(addr + addr_length) = dsp->ds_sap;
1219 	}
1220 
1221 done:
1222 	ASSERT(IMPLY(dlp->dl_qos_offset != 0, dlp->dl_qos_length != 0));
1223 	ASSERT(IMPLY(dlp->dl_qos_range_offset != 0,
1224 	    dlp->dl_qos_range_length != 0));
1225 	ASSERT(IMPLY(dlp->dl_addr_offset != 0, dlp->dl_addr_length != 0));
1226 	ASSERT(IMPLY(dlp->dl_brdcst_addr_offset != 0,
1227 	    dlp->dl_brdcst_addr_length != 0));
1228 
1229 	qreply(dsp->ds_wq, mp);
1230 }
1231 
1232 /*
1233  * DL_OK_ACK/DL_ERROR_ACK
1234  */
1235 static void
1236 proto_attach_ack(dld_str_t *dsp, mblk_t *mp, int err)
1237 {
1238 	int		dl_err;
1239 
1240 	if (err != 0)
1241 		goto failed;
1242 
1243 	dsp->ds_dlstate = DL_UNBOUND;
1244 	dlokack(dsp->ds_wq, mp, DL_ATTACH_REQ);
1245 	return;
1246 
1247 failed:
1248 	switch (err) {
1249 	case ENOENT:
1250 		dl_err = DL_BADPPA;
1251 		err = 0;
1252 		break;
1253 
1254 	default:
1255 		dl_err = DL_SYSERR;
1256 		break;
1257 	}
1258 
1259 	dsp->ds_dlstate = DL_UNATTACHED;
1260 	dlerrorack(dsp->ds_wq, mp, DL_ATTACH_REQ, dl_err, err);
1261 }
1262 
1263 /*
1264  * DL_OK_ACK
1265  */
1266 static void
1267 proto_detach_ack(dld_str_t *dsp, mblk_t *mp)
1268 {
1269 	dsp->ds_dlstate = DL_UNATTACHED;
1270 	dlokack(dsp->ds_wq, mp, DL_DETACH_REQ);
1271 }
1272 
1273 /*
1274  * DL_BIND_ACK/DL_ERROR_ACK
1275  */
1276 static void
1277 proto_bind_ack(dld_str_t *dsp, mblk_t *mp, int err)
1278 {
1279 	uint8_t			addr[MAXADDRLEN];
1280 	uint_t			addr_length;
1281 	int			dl_err;
1282 
1283 	if (err != 0)
1284 		goto failed;
1285 
1286 	/*
1287 	 * Copy in MAC address.
1288 	 */
1289 	addr_length = dsp->ds_mip->mi_addr_length;
1290 	bcopy(dsp->ds_curr_addr, addr, addr_length);
1291 
1292 	/*
1293 	 * Copy in the DLSAP.
1294 	 */
1295 	*(uint16_t *)(addr + addr_length) = dsp->ds_sap;
1296 	addr_length += sizeof (uint16_t);
1297 
1298 	dsp->ds_dlstate = DL_IDLE;
1299 	dlbindack(dsp->ds_wq, mp, dsp->ds_sap, (void *)addr, addr_length, 0,
1300 	    0);
1301 	return;
1302 
1303 failed:
1304 	switch (err) {
1305 	case EINVAL:
1306 		dl_err = DL_BADADDR;
1307 		err = 0;
1308 		break;
1309 
1310 	default:
1311 		dl_err = DL_SYSERR;
1312 		break;
1313 	}
1314 
1315 	dsp->ds_dlstate = DL_UNBOUND;
1316 	dlerrorack(dsp->ds_wq, mp, DL_BIND_REQ, dl_err, err);
1317 }
1318 
1319 /*
1320  * DL_OK_ACK
1321  */
1322 static void
1323 proto_unbind_ack(dld_str_t *dsp, mblk_t *mp)
1324 {
1325 	dsp->ds_dlstate = DL_UNBOUND;
1326 	dlokack(dsp->ds_wq, mp, DL_UNBIND_REQ);
1327 }
1328 
1329 /*
1330  * DL_OK_ACK/DL_ERROR_ACK
1331  */
1332 static void
1333 proto_promiscon_ack(dld_str_t *dsp, mblk_t *mp, int err)
1334 {
1335 	if (err != 0)
1336 		goto failed;
1337 
1338 	dlokack(dsp->ds_wq, mp, DL_PROMISCON_REQ);
1339 	return;
1340 
1341 failed:
1342 	dlerrorack(dsp->ds_wq, mp, DL_PROMISCON_REQ, DL_SYSERR, err);
1343 }
1344 
1345 /*
1346  * DL_OK_ACK/DL_ERROR_ACK
1347  */
1348 static void
1349 proto_promiscoff_ack(dld_str_t *dsp, mblk_t *mp, int err)
1350 {
1351 	if (err != 0)
1352 		goto failed;
1353 
1354 	dlokack(dsp->ds_wq, mp, DL_PROMISCOFF_REQ);
1355 	return;
1356 
1357 failed:
1358 	dlerrorack(dsp->ds_wq, mp, DL_PROMISCOFF_REQ, DL_SYSERR, err);
1359 }
1360 
1361 /*
1362  * DL_OK_ACK/DL_ERROR_ACK
1363  */
1364 static void
1365 proto_enabmulti_ack(dld_str_t *dsp, mblk_t *mp, int err)
1366 {
1367 	int		dl_err;
1368 
1369 	if (err != 0)
1370 		goto failed;
1371 
1372 	dlokack(dsp->ds_wq, mp, DL_ENABMULTI_REQ);
1373 	return;
1374 
1375 failed:
1376 	switch (err) {
1377 	case EINVAL:
1378 		dl_err = DL_BADADDR;
1379 		err = 0;
1380 		break;
1381 
1382 	case ENOSPC:
1383 		dl_err = DL_TOOMANY;
1384 		err = 0;
1385 		break;
1386 
1387 	default:
1388 		dl_err = DL_SYSERR;
1389 		break;
1390 	}
1391 
1392 	dlerrorack(dsp->ds_wq, mp, DL_ENABMULTI_REQ, dl_err, err);
1393 }
1394 
1395 /*
1396  * DL_OK_ACK/DL_ERROR_ACK
1397  */
1398 static void
1399 proto_disabmulti_ack(dld_str_t *dsp, mblk_t *mp, int err)
1400 {
1401 	int		dl_err;
1402 
1403 	if (err != 0)
1404 		goto failed;
1405 
1406 	dlokack(dsp->ds_wq, mp, DL_DISABMULTI_REQ);
1407 	return;
1408 
1409 failed:
1410 	switch (err) {
1411 	case EINVAL:
1412 		dl_err = DL_BADADDR;
1413 		err = 0;
1414 		break;
1415 
1416 	case ENOENT:
1417 		dl_err = DL_NOTENAB;
1418 		err = 0;
1419 		break;
1420 
1421 	default:
1422 		dl_err = DL_SYSERR;
1423 		break;
1424 	}
1425 
1426 	dlerrorack(dsp->ds_wq, mp, DL_DISABMULTI_REQ, dl_err, err);
1427 }
1428 
1429 /*
1430  * DL_PHYS_ADDR_ACK
1431  */
1432 static void
1433 proto_physaddr_ack(dld_str_t *dsp, mblk_t *mp, t_uscalar_t type)
1434 {
1435 	uint_t			addr_length;
1436 
1437 	/*
1438 	 * Copy in the address.
1439 	 */
1440 	addr_length = dsp->ds_mip->mi_addr_length;
1441 	dlphysaddrack(dsp->ds_wq, mp, (type == DL_CURR_PHYS_ADDR) ?
1442 	    dsp->ds_curr_addr : dsp->ds_fact_addr, addr_length);
1443 }
1444 
1445 /*
1446  * DL_OK_ACK/DL_ERROR_ACK
1447  */
1448 static void
1449 proto_setphysaddr_ack(dld_str_t *dsp, mblk_t *mp, int err)
1450 {
1451 	int		dl_err;
1452 
1453 	if (err != 0)
1454 		goto failed;
1455 
1456 	dlokack(dsp->ds_wq, mp, DL_SET_PHYS_ADDR_REQ);
1457 	return;
1458 
1459 failed:
1460 	switch (err) {
1461 	case EINVAL:
1462 		dl_err = DL_BADADDR;
1463 		err = 0;
1464 		break;
1465 
1466 	default:
1467 		dl_err = DL_SYSERR;
1468 		break;
1469 	}
1470 
1471 	dlerrorack(dsp->ds_wq, mp, DL_SET_PHYS_ADDR_REQ, dl_err, err);
1472 }
1473 
1474 /*
1475  * DL_OK_ACK
1476  */
1477 static void
1478 proto_udqos_ack(dld_str_t *dsp, mblk_t *mp)
1479 {
1480 	dlokack(dsp->ds_wq, mp, DL_UDQOS_REQ);
1481 }
1482 
1483 static void
1484 proto_poll_disable(dld_str_t *dsp)
1485 {
1486 	mac_handle_t	mh;
1487 
1488 	if (!dsp->ds_polling)
1489 		return;
1490 
1491 	/*
1492 	 * It should be impossible to enable raw mode if polling is turned on.
1493 	 */
1494 	ASSERT(dsp->ds_mode != DLD_RAW);
1495 
1496 	/*
1497 	 * Reset the resource_add callback.
1498 	 */
1499 	mh = dls_mac(dsp->ds_dc);
1500 	mac_resource_set(mh, NULL, NULL);
1501 
1502 	/*
1503 	 * Set receive function back to default.
1504 	 */
1505 	dls_rx_set(dsp->ds_dc, (dsp->ds_mode == DLD_FASTPATH) ?
1506 	    dld_str_rx_fastpath : dld_str_rx_unitdata, (void *)dsp);
1507 
1508 	/*
1509 	 * Note that polling is disabled.
1510 	 */
1511 	dsp->ds_polling = B_FALSE;
1512 }
1513 
1514 static boolean_t
1515 proto_poll_enable(dld_str_t *dsp, dl_capab_poll_t *pollp)
1516 {
1517 	mac_handle_t	mh;
1518 
1519 	ASSERT(!dsp->ds_polling);
1520 
1521 	/*
1522 	 * We cannot enable polling if raw mode
1523 	 * has been enabled.
1524 	 */
1525 	if (dsp->ds_mode == DLD_RAW)
1526 		return (B_FALSE);
1527 
1528 	mh = dls_mac(dsp->ds_dc);
1529 
1530 	/*
1531 	 * Register resources.
1532 	 */
1533 	mac_resource_set(mh, (mac_resource_add_t)pollp->poll_ring_add,
1534 	    (void *)pollp->poll_rx_handle);
1535 	mac_resources(mh);
1536 
1537 	/*
1538 	 * Set the receive function.
1539 	 */
1540 	dls_rx_set(dsp->ds_dc, (dls_rx_t)pollp->poll_rx,
1541 	    (void *)pollp->poll_rx_handle);
1542 
1543 	/*
1544 	 * Note that polling is enabled. This prevents further DLIOCHDRINFO
1545 	 * ioctls from overwriting the receive function pointer.
1546 	 */
1547 	dsp->ds_polling = B_TRUE;
1548 	return (B_TRUE);
1549 }
1550 
1551 /*
1552  * DL_CAPABILITY_ACK/DL_ERROR_ACK
1553  */
1554 static void
1555 proto_capability_ack(dld_str_t *dsp, mblk_t *mp)
1556 {
1557 	dl_capability_ack_t	*dlap;
1558 	dl_capability_sub_t	*dlsp;
1559 	size_t			subsize;
1560 	dl_capab_poll_t		poll;
1561 	dl_capab_hcksum_t	hcksum;
1562 	dl_capab_zerocopy_t	zcopy;
1563 	uint8_t			*ptr;
1564 	uint32_t		cksum;
1565 	boolean_t		poll_cap;
1566 
1567 	/*
1568 	 * Initially assume no capabilities.
1569 	 */
1570 	subsize = 0;
1571 
1572 	/*
1573 	 * Check if polling can be enabled on this interface.
1574 	 * If advertising DL_CAPAB_POLL has not been explicitly disabled
1575 	 * then reserve space for that capability.
1576 	 */
1577 	poll_cap = ((dsp->ds_mip->mi_poll & DL_CAPAB_POLL) &&
1578 	    !(dld_opt & DLD_OPT_NO_POLL) && (dsp->ds_vid == VLAN_ID_NONE));
1579 	if (poll_cap) {
1580 		subsize += sizeof (dl_capability_sub_t) +
1581 		    sizeof (dl_capab_poll_t);
1582 	}
1583 
1584 	/*
1585 	 * If the MAC interface supports checksum offload then reserve
1586 	 * space for the DL_CAPAB_HCKSUM capability.
1587 	 */
1588 	if ((cksum = dsp->ds_mip->mi_cksum) != 0) {
1589 		subsize += sizeof (dl_capability_sub_t) +
1590 		    sizeof (dl_capab_hcksum_t);
1591 	}
1592 
1593 	/*
1594 	 * If DL_CAPAB_ZEROCOPY has not be explicitly disabled then
1595 	 * reserve space for it.
1596 	 */
1597 	if (!(dld_opt & DLD_OPT_NO_ZEROCOPY)) {
1598 		subsize += sizeof (dl_capability_sub_t) +
1599 		    sizeof (dl_capab_zerocopy_t);
1600 	}
1601 
1602 	/*
1603 	 * If there are no capabilities to advertise, send a DL_ERROR_ACK.
1604 	 */
1605 	if (subsize == 0) {
1606 		dlerrorack(dsp->ds_wq, mp, DL_CAPABILITY_REQ, DL_NOTSUPPORTED,
1607 		    0);
1608 		return;
1609 	}
1610 
1611 	if ((mp = mexchange(dsp->ds_wq, mp,
1612 	    sizeof (dl_capability_ack_t) + subsize, M_PROTO, 0)) == NULL)
1613 		return;
1614 
1615 	bzero(mp->b_rptr, sizeof (dl_capability_ack_t));
1616 	dlap = (dl_capability_ack_t *)mp->b_rptr;
1617 	dlap->dl_primitive = DL_CAPABILITY_ACK;
1618 	dlap->dl_sub_offset = sizeof (dl_capability_ack_t);
1619 	dlap->dl_sub_length = subsize;
1620 	ptr = (uint8_t *)&dlap[1];
1621 
1622 	/*
1623 	 * IP polling interface.
1624 	 */
1625 	if (poll_cap) {
1626 		/*
1627 		 * Attempt to disable just in case this is a re-negotiation.
1628 		 */
1629 		proto_poll_disable(dsp);
1630 
1631 		dlsp = (dl_capability_sub_t *)ptr;
1632 
1633 		dlsp->dl_cap = DL_CAPAB_POLL;
1634 		dlsp->dl_length = sizeof (dl_capab_poll_t);
1635 		ptr += sizeof (dl_capability_sub_t);
1636 
1637 		bzero(&poll, sizeof (dl_capab_poll_t));
1638 		poll.poll_version = POLL_VERSION_1;
1639 		poll.poll_flags = POLL_CAPABLE;
1640 		poll.poll_tx_handle = (uintptr_t)dsp->ds_dc;
1641 		poll.poll_tx = (uintptr_t)dls_tx;
1642 
1643 		dlcapabsetqid(&(poll.poll_mid), dsp->ds_rq);
1644 		bcopy(&poll, ptr, sizeof (dl_capab_poll_t));
1645 		ptr += sizeof (dl_capab_poll_t);
1646 	}
1647 
1648 	/*
1649 	 * TCP/IP checksum offload.
1650 	 */
1651 	if (cksum != 0) {
1652 		dlsp = (dl_capability_sub_t *)ptr;
1653 
1654 		dlsp->dl_cap = DL_CAPAB_HCKSUM;
1655 		dlsp->dl_length = sizeof (dl_capab_hcksum_t);
1656 		ptr += sizeof (dl_capability_sub_t);
1657 
1658 		bzero(&hcksum, sizeof (dl_capab_hcksum_t));
1659 		hcksum.hcksum_version = HCKSUM_VERSION_1;
1660 		hcksum.hcksum_txflags = cksum;
1661 
1662 		dlcapabsetqid(&(hcksum.hcksum_mid), dsp->ds_rq);
1663 		bcopy(&hcksum, ptr, sizeof (dl_capab_hcksum_t));
1664 		ptr += sizeof (dl_capab_hcksum_t);
1665 	}
1666 
1667 	/*
1668 	 * Zero copy
1669 	 */
1670 	if (!(dld_opt & DLD_OPT_NO_ZEROCOPY)) {
1671 		dlsp = (dl_capability_sub_t *)ptr;
1672 
1673 		dlsp->dl_cap = DL_CAPAB_ZEROCOPY;
1674 		dlsp->dl_length = sizeof (dl_capab_zerocopy_t);
1675 		ptr += sizeof (dl_capability_sub_t);
1676 
1677 		bzero(&zcopy, sizeof (dl_capab_zerocopy_t));
1678 		zcopy.zerocopy_version = ZEROCOPY_VERSION_1;
1679 		zcopy.zerocopy_flags = DL_CAPAB_VMSAFE_MEM;
1680 
1681 		dlcapabsetqid(&(zcopy.zerocopy_mid), dsp->ds_rq);
1682 		bcopy(&zcopy, ptr, sizeof (dl_capab_zerocopy_t));
1683 		ptr += sizeof (dl_capab_zerocopy_t);
1684 	}
1685 
1686 	ASSERT(ptr == mp->b_rptr + sizeof (dl_capability_ack_t) + subsize);
1687 	qreply(dsp->ds_wq, mp);
1688 }
1689 
1690 /*
1691  * DL_CAPABILITY_ACK/DL_ERROR_ACK
1692  */
1693 static void
1694 proto_capability_enable(dld_str_t *dsp, mblk_t *mp)
1695 {
1696 	dl_capability_req_t	*dlp = (dl_capability_req_t *)mp->b_rptr;
1697 	dl_capability_sub_t	*sp;
1698 	size_t			size;
1699 	offset_t		off;
1700 	size_t			len;
1701 	offset_t		end;
1702 
1703 	dlp->dl_primitive = DL_CAPABILITY_ACK;
1704 
1705 	off = dlp->dl_sub_offset;
1706 	len = dlp->dl_sub_length;
1707 
1708 	/*
1709 	 * Walk the list of capabilities to be enabled.
1710 	 */
1711 	for (end = off + len; off < end; ) {
1712 		sp = (dl_capability_sub_t *)(mp->b_rptr + off);
1713 		size = sizeof (dl_capability_sub_t) + sp->dl_length;
1714 
1715 		if (off + size > end ||
1716 		    !IS_P2ALIGNED(off, sizeof (uint32_t))) {
1717 			dlerrorack(dsp->ds_wq, mp, DL_CAPABILITY_REQ,
1718 			    DL_BADPRIM, 0);
1719 			return;
1720 		}
1721 
1722 		switch (sp->dl_cap) {
1723 
1724 		/*
1725 		 * TCP/IP checksum offload to hardware.
1726 		 */
1727 		case DL_CAPAB_HCKSUM: {
1728 			dl_capab_hcksum_t 	*hcksump;
1729 			dl_capab_hcksum_t	hcksum;
1730 
1731 			ASSERT(dsp->ds_mip->mi_cksum != 0);
1732 
1733 			hcksump = (dl_capab_hcksum_t *)&sp[1];
1734 
1735 			/*
1736 			 * Copy for alignment.
1737 			 */
1738 			bcopy(hcksump, &hcksum, sizeof (dl_capab_hcksum_t));
1739 			dlcapabsetqid(&(hcksum.hcksum_mid), dsp->ds_rq);
1740 			bcopy(&hcksum, hcksump, sizeof (dl_capab_hcksum_t));
1741 			break;
1742 		}
1743 
1744 		/*
1745 		 * IP polling interface.
1746 		 */
1747 		case DL_CAPAB_POLL: {
1748 			dl_capab_poll_t 	*pollp;
1749 			dl_capab_poll_t		poll;
1750 
1751 			pollp = (dl_capab_poll_t *)&sp[1];
1752 
1753 			/*
1754 			 * Copy for alignment.
1755 			 */
1756 			bcopy(pollp, &poll, sizeof (dl_capab_poll_t));
1757 
1758 			switch (poll.poll_flags) {
1759 			default:
1760 				/*FALLTHRU*/
1761 			case POLL_DISABLE:
1762 				proto_poll_disable(dsp);
1763 				break;
1764 
1765 			case POLL_ENABLE:
1766 				ASSERT(!(dld_opt & DLD_OPT_NO_POLL));
1767 
1768 				/*
1769 				 * Make sure polling is disabled.
1770 				 */
1771 				proto_poll_disable(dsp);
1772 
1773 				/*
1774 				 * Now attempt enable it.
1775 				 */
1776 				if (!proto_poll_enable(dsp, &poll))
1777 					break;
1778 
1779 				bzero(&poll, sizeof (dl_capab_poll_t));
1780 				poll.poll_flags = POLL_ENABLE;
1781 				break;
1782 			}
1783 
1784 			dlcapabsetqid(&(poll.poll_mid), dsp->ds_rq);
1785 			bcopy(&poll, pollp, sizeof (dl_capab_poll_t));
1786 			break;
1787 		}
1788 		default:
1789 			break;
1790 		}
1791 
1792 		off += size;
1793 	}
1794 
1795 	qreply(dsp->ds_wq, mp);
1796 }
1797 
1798 /*
1799  * DL_NOTIFY_ACK
1800  */
1801 static void
1802 proto_notify_ack(dld_str_t *dsp, mblk_t *mp, uint_t enable_set, uint_t ack_set)
1803 {
1804 	/*
1805 	 * Cache the notifications that are being enabled.
1806 	 */
1807 	dsp->ds_notifications = enable_set;
1808 
1809 	/*
1810 	 * The ACK carries all notifications regardless of which set is
1811 	 * being enabled.
1812 	 */
1813 	dlnotifyack(dsp->ds_wq, mp, ack_set);
1814 
1815 	/*
1816 	 * Solicit DL_NOTIFY_IND messages for each enabled notification.
1817 	 */
1818 	if (dsp->ds_notifications != 0)
1819 		dld_str_notify_ind(dsp);
1820 }
1821