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