xref: /illumos-gate/usr/src/uts/common/io/dld/dld_str.c (revision 6a1c6faa6f0834799d7de3e77fac2ec32d923f9a)
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/stream.h>
35 #include	<sys/stropts.h>
36 #include	<sys/strsun.h>
37 #include	<sys/strsubr.h>
38 #include	<sys/atomic.h>
39 #include	<sys/sdt.h>
40 #include	<sys/mac.h>
41 #include	<sys/dls.h>
42 #include	<sys/dld.h>
43 #include	<sys/dld_impl.h>
44 #include	<sys/taskq.h>
45 #include	<sys/vlan.h>
46 
47 static int	str_constructor(void *, void *, int);
48 static void	str_destructor(void *, void *);
49 static void	str_m_put(dld_str_t *, mblk_t *);
50 static void	str_m_srv(dld_str_t *, mblk_t *);
51 static void	str_mdata_fastpath_put(dld_str_t *, mblk_t *);
52 static void	str_mdata_raw_put(dld_str_t *, mblk_t *);
53 static void	str_mdata_srv(dld_str_t *, mblk_t *);
54 static void	str_mproto_put(dld_str_t *, mblk_t *);
55 static void	str_mpcproto_put(dld_str_t *, mblk_t *);
56 static void	str_mioctl_put(dld_str_t *, mblk_t *);
57 static void	str_mflush_put(dld_str_t *, mblk_t *);
58 static mblk_t	*str_unitdata_ind(dld_str_t *, mblk_t *);
59 static void	str_notify_promisc_on_phys(dld_str_t *);
60 static void	str_notify_promisc_off_phys(dld_str_t *);
61 static void	str_notify_phys_addr(dld_str_t *, const uint8_t *);
62 static void	str_notify_link_up(dld_str_t *);
63 static void	str_notify_link_down(dld_str_t *);
64 static void	str_notify_capab_reneg(dld_str_t *);
65 static void	str_notify_speed(dld_str_t *, uint32_t);
66 static void	str_notify(void *, mac_notify_type_t);
67 static void	str_putbq(queue_t *q, mblk_t *mp);
68 
69 static uint32_t		str_count;
70 static kmem_cache_t	*str_cachep;
71 
72 typedef struct str_msg_info {
73 	uint8_t		smi_type;
74 	const char	*smi_txt;
75 	void		(*smi_put)(dld_str_t *, mblk_t *);
76 	void		(*smi_srv)(dld_str_t *, mblk_t *);
77 } str_msg_info_t;
78 
79 /*
80  * Normal priority message jump table.
81  */
82 str_msg_info_t	str_mi[] = {
83 	{ M_DATA, "M_DATA", str_m_put, str_m_srv },
84 	{ M_PROTO, "M_PROTO", str_mproto_put, str_m_srv },
85 	{ 0x02, "undefined", str_m_put, str_m_srv },
86 	{ 0x03, "undefined", str_m_put, str_m_srv },
87 	{ 0x04, "undefined", str_m_put, str_m_srv },
88 	{ 0x05, "undefined", str_m_put, str_m_srv },
89 	{ 0x06, "undefined", str_m_put, str_m_srv },
90 	{ 0x07, "undefined", str_m_put, str_m_srv },
91 	{ M_BREAK, "M_BREAK", str_m_put, str_m_srv },
92 	{ M_PASSFP, "M_PASSFP", str_m_put, str_m_srv },
93 	{ M_EVENT, "M_EVENT", str_m_put, str_m_srv },
94 	{ M_SIG, "M_SIG", str_m_put, str_m_srv },
95 	{ M_DELAY, "M_DELAY", str_m_put, str_m_srv },
96 	{ M_CTL, "M_CTL", str_m_put, str_m_srv },
97 	{ M_IOCTL, "M_IOCTL", str_mioctl_put, str_m_srv },
98 	{ M_SETOPTS, "M_SETOPTS", str_m_put, str_m_srv },
99 	{ M_RSE, "M_RSE", str_m_put, str_m_srv }
100 };
101 
102 #define	STR_MI_COUNT	(sizeof (str_mi) / sizeof (str_mi[0]))
103 
104 /*
105  * High priority message jump table.
106  */
107 str_msg_info_t	str_pmi[] = {
108 	{ 0x80,	 "undefined", str_m_put, str_m_srv },
109 	{ M_IOCACK, "M_IOCACK", str_m_put, str_m_srv },
110 	{ M_IOCNAK, "M_IOCNAK", str_m_put, str_m_srv },
111 	{ M_PCPROTO, "M_PCPROTO", str_mpcproto_put, str_m_srv },
112 	{ M_PCSIG, "M_PCSIG", str_m_put, str_m_srv },
113 	{ M_READ, "M_READ", str_m_put, str_m_srv },
114 	{ M_FLUSH, "M_FLUSH", str_mflush_put, str_m_srv },
115 	{ M_STOP, "M_STOP", str_m_put, str_m_srv },
116 	{ M_START, "M_START", str_m_put, str_m_srv },
117 	{ M_HANGUP, "M_HANGUP", str_m_put, str_m_srv },
118 	{ M_ERROR, "M_ERROR", str_m_put, str_m_srv },
119 	{ M_COPYIN, "M_COPYIN", str_m_put, str_m_srv },
120 	{ M_COPYOUT, "M_COPYOUT", str_m_put, str_m_srv },
121 	{ M_IOCDATA, "M_IOCDATA", str_m_put, str_m_srv },
122 	{ M_PCRSE, "M_PCRSE", str_m_put, str_m_srv },
123 	{ M_STOPI, "M_STOPI", str_m_put, str_m_srv },
124 	{ M_STARTI, "M_STARTI", str_m_put, str_m_srv },
125 	{ M_PCEVENT, "M_PCEVENT", str_m_put, str_m_srv },
126 	{ M_UNHANGUP, "M_UNHANGUP", str_m_put, str_m_srv }
127 };
128 
129 #define	STR_PMI_COUNT	(sizeof (str_pmi) / sizeof (str_pmi[0]))
130 
131 /*
132  * Initialize this module's data structures.
133  */
134 void
135 dld_str_init(void)
136 {
137 	/*
138 	 * Create dld_str_t object cache.
139 	 */
140 	str_cachep = kmem_cache_create("dld_str_cache", sizeof (dld_str_t),
141 	    0, str_constructor, str_destructor, NULL, NULL, NULL, 0);
142 	ASSERT(str_cachep != NULL);
143 }
144 
145 /*
146  * Tear down this module's data structures.
147  */
148 int
149 dld_str_fini(void)
150 {
151 	/*
152 	 * Make sure that there are no objects in use.
153 	 */
154 	if (str_count != 0)
155 		return (EBUSY);
156 
157 	/*
158 	 * Destroy object cache.
159 	 */
160 	kmem_cache_destroy(str_cachep);
161 
162 	return (0);
163 }
164 
165 /*
166  * Create a new dld_str_t object.
167  */
168 dld_str_t *
169 dld_str_create(queue_t *rq)
170 {
171 	dld_str_t	*dsp;
172 
173 	/*
174 	 * Allocate an object from the cache.
175 	 */
176 	dsp = kmem_cache_alloc(str_cachep, KM_SLEEP);
177 	atomic_add_32(&str_count, 1);
178 
179 	/*
180 	 * Initialize the queue pointers.
181 	 */
182 	ASSERT(RD(rq) == rq);
183 	dsp->ds_rq = rq;
184 	dsp->ds_wq = WR(rq);
185 	rq->q_ptr = WR(rq)->q_ptr = (void *)dsp;
186 
187 	return (dsp);
188 }
189 
190 /*
191  * Destroy a dld_str_t object.
192  */
193 void
194 dld_str_destroy(dld_str_t *dsp)
195 {
196 	queue_t		*rq;
197 	queue_t		*wq;
198 
199 	/*
200 	 * Clear the queue pointers.
201 	 */
202 	rq = dsp->ds_rq;
203 	wq = dsp->ds_wq;
204 	ASSERT(wq == WR(rq));
205 
206 	rq->q_ptr = wq->q_ptr = NULL;
207 	dsp->ds_rq = dsp->ds_wq = NULL;
208 
209 	/*
210 	 * Reinitialize all the flags.
211 	 */
212 	dsp->ds_notifications = 0;
213 	dsp->ds_passivestate = DLD_UNINITIALIZED;
214 	dsp->ds_mode = DLD_UNITDATA;
215 
216 	/*
217 	 * Free the object back to the cache.
218 	 */
219 	kmem_cache_free(str_cachep, dsp);
220 	atomic_add_32(&str_count, -1);
221 }
222 
223 /*
224  * kmem_cache contructor function: see kmem_cache_create(9f).
225  */
226 /*ARGSUSED*/
227 static int
228 str_constructor(void *buf, void *cdrarg, int kmflags)
229 {
230 	dld_str_t	*dsp = buf;
231 
232 	bzero(buf, sizeof (dld_str_t));
233 
234 	/*
235 	 * Take a copy of the global message handler jump tables.
236 	 */
237 	ASSERT(dsp->ds_mi == NULL);
238 	if ((dsp->ds_mi = kmem_zalloc(sizeof (str_mi), kmflags)) == NULL)
239 		return (-1);
240 
241 	bcopy(str_mi, dsp->ds_mi, sizeof (str_mi));
242 
243 	ASSERT(dsp->ds_pmi == NULL);
244 	if ((dsp->ds_pmi = kmem_zalloc(sizeof (str_pmi), kmflags)) == NULL) {
245 		kmem_free(dsp->ds_mi, sizeof (str_mi));
246 		dsp->ds_mi = NULL;
247 		return (-1);
248 	}
249 
250 	bcopy(str_pmi, dsp->ds_pmi, sizeof (str_pmi));
251 
252 	/*
253 	 * Allocate a new minor number.
254 	 */
255 	if ((dsp->ds_minor = dld_minor_hold(kmflags == KM_SLEEP)) == 0) {
256 		kmem_free(dsp->ds_mi, sizeof (str_mi));
257 		dsp->ds_mi = NULL;
258 		kmem_free(dsp->ds_pmi, sizeof (str_pmi));
259 		dsp->ds_pmi = NULL;
260 		return (-1);
261 	}
262 
263 	/*
264 	 * Initialize the DLPI state machine.
265 	 */
266 	dsp->ds_dlstate = DL_UNATTACHED;
267 
268 	return (0);
269 }
270 
271 /*
272  * kmem_cache destructor function.
273  */
274 /*ARGSUSED*/
275 static void
276 str_destructor(void *buf, void *cdrarg)
277 {
278 	dld_str_t	*dsp = buf;
279 
280 	/*
281 	 * Make sure the DLPI state machine was reset.
282 	 */
283 	ASSERT(dsp->ds_dlstate == DL_UNATTACHED);
284 
285 	/*
286 	 * Make sure the data-link interface was closed.
287 	 */
288 	ASSERT(dsp->ds_mh == NULL);
289 	ASSERT(dsp->ds_dc == NULL);
290 
291 	/*
292 	 * Make sure enabled notifications are cleared.
293 	 */
294 	ASSERT(dsp->ds_notifications == 0);
295 
296 	/*
297 	 * Make sure polling is disabled.
298 	 */
299 	ASSERT(!dsp->ds_polling);
300 
301 	/*
302 	 * Make sure M_DATA message handling is disabled.
303 	 */
304 	ASSERT(dsp->ds_mi[M_DATA].smi_put == str_m_put);
305 	ASSERT(dsp->ds_mi[M_DATA].smi_srv == str_m_srv);
306 
307 	/*
308 	 * Release the minor number.
309 	 */
310 	dld_minor_rele(dsp->ds_minor);
311 
312 	/*
313 	 * Clear down the jump tables.
314 	 */
315 	kmem_free(dsp->ds_mi, sizeof (str_mi));
316 	dsp->ds_mi = NULL;
317 
318 	kmem_free(dsp->ds_pmi, sizeof (str_pmi));
319 	dsp->ds_pmi = NULL;
320 }
321 
322 /*
323  * Called from put(9e) to process a streams message.
324  */
325 void
326 dld_str_put(dld_str_t *dsp, mblk_t *mp)
327 {
328 	uint8_t		type;
329 	str_msg_info_t	*smip;
330 
331 	/*
332 	 * Look up the message handler from the appropriate jump table.
333 	 */
334 	if ((type = DB_TYPE(mp)) & QPCTL) {
335 		/*
336 		 * Clear the priority bit to index into the jump table.
337 		 */
338 		type &= ~QPCTL;
339 
340 		/*
341 		 * Check the message is not out of range for the jump table.
342 		 */
343 		if (type >= STR_PMI_COUNT)
344 			goto unknown;
345 
346 		/*
347 		 * Get the handler from the jump table.
348 		 */
349 		smip = &(dsp->ds_pmi[type]);
350 
351 		/*
352 		 * OR the priorty bit back in to restore the original message
353 		 * type.
354 		 */
355 		type |= QPCTL;
356 	} else {
357 		/*
358 		 * Check the message is not out of range for the jump table.
359 		 */
360 		if (type >= STR_MI_COUNT)
361 			goto unknown;
362 
363 		/*
364 		 * Get the handler from the jump table.
365 		 */
366 		smip = &(dsp->ds_mi[type]);
367 	}
368 
369 	ASSERT(smip->smi_type == type);
370 	smip->smi_put(dsp, mp);
371 	return;
372 
373 unknown:
374 	str_m_put(dsp, mp);
375 }
376 
377 /*
378  * Called from srv(9e) to process a streams message.
379  */
380 void
381 dld_str_srv(dld_str_t *dsp, mblk_t *mp)
382 {
383 	uint8_t		type;
384 	str_msg_info_t	*smip;
385 
386 	/*
387 	 * Look up the message handler from the appropriate jump table.
388 	 */
389 	if ((type = DB_TYPE(mp)) & QPCTL) {
390 		/*
391 		 * Clear the priority bit to index into the jump table.
392 		 */
393 		type &= ~QPCTL;
394 
395 		/*
396 		 * Check the message is not out of range for the jump table.
397 		 */
398 		if (type >= STR_PMI_COUNT)
399 			goto unknown;
400 
401 		/*
402 		 * Get the handler from the jump table.
403 		 */
404 		smip = &(dsp->ds_pmi[type]);
405 
406 		/*
407 		 * OR the priorty bit back in to restore the original message
408 		 * type.
409 		 */
410 		type |= QPCTL;
411 	} else {
412 		/*
413 		 * Check the message is not out of range for the jump table.
414 		 */
415 		if (type >= STR_MI_COUNT)
416 			goto unknown;
417 
418 		/*
419 		 * Get the handler from the jump table.
420 		 */
421 		ASSERT(type < STR_MI_COUNT);
422 		smip = &(dsp->ds_mi[type]);
423 	}
424 
425 	ASSERT(smip->smi_type == type);
426 	smip->smi_srv(dsp, mp);
427 	return;
428 
429 unknown:
430 	str_m_srv(dsp, mp);
431 }
432 
433 /*
434  * M_DATA put (IP fast-path mode)
435  */
436 static void
437 str_mdata_fastpath_put(dld_str_t *dsp, mblk_t *mp)
438 {
439 	queue_t		*q = dsp->ds_wq;
440 
441 	/*
442 	 * If something is already queued then we must queue to avoid
443 	 * re-ordering.
444 	 */
445 	if (q->q_first != NULL) {
446 		(void) putq(q, mp);
447 		return;
448 	}
449 
450 	/*
451 	 * Attempt to transmit the packet.
452 	 */
453 	if ((mp = dls_tx(dsp->ds_dc, mp)) != NULL) {
454 		(void) putbq(q, mp);
455 		qenable(q);
456 	}
457 }
458 
459 /*
460  * M_DATA put (raw mode)
461  */
462 static void
463 str_mdata_raw_put(dld_str_t *dsp, mblk_t *mp)
464 {
465 	queue_t			*q = dsp->ds_wq;
466 	struct ether_header	*ehp;
467 	mblk_t			*bp;
468 	size_t			size;
469 	size_t			hdrlen;
470 
471 	size = MBLKL(mp);
472 	if (size < sizeof (struct ether_header))
473 		goto discard;
474 
475 	hdrlen = sizeof (struct ether_header);
476 
477 	ehp = (struct ether_header *)mp->b_rptr;
478 	if (ntohs(ehp->ether_type) == VLAN_TPID) {
479 		struct ether_vlan_header	*evhp;
480 
481 		if (size < sizeof (struct ether_vlan_header))
482 			goto discard;
483 
484 		/*
485 		 * Replace vtag with our own
486 		 */
487 		evhp = (struct ether_vlan_header *)ehp;
488 		evhp->ether_tci = htons(VLAN_TCI(dsp->ds_pri,
489 		    ETHER_CFI, dsp->ds_vid));
490 		hdrlen = sizeof (struct ether_vlan_header);
491 	}
492 
493 	/*
494 	 * Check the packet is not too big and that any remaining
495 	 * fragment list is composed entirely of M_DATA messages. (We
496 	 * know the first fragment was M_DATA otherwise we could not
497 	 * have got here).
498 	 */
499 	for (bp = mp->b_next; bp != NULL; bp = bp->b_cont) {
500 		if (DB_TYPE(bp) != M_DATA)
501 			goto discard;
502 		size += MBLKL(bp);
503 	}
504 
505 	if (size > dsp->ds_mip->mi_sdu_max + hdrlen)
506 		goto discard;
507 
508 	/*
509 	 * If something is already queued then we must queue to avoid
510 	 * re-ordering.
511 	 */
512 	if (q->q_first != NULL) {
513 		(void) putq(q, bp);
514 		return;
515 	}
516 
517 	/*
518 	 * Attempt to transmit the packet.
519 	 */
520 	if ((mp = dls_tx(dsp->ds_dc, mp)) != NULL) {
521 		(void) putbq(q, mp);
522 		qenable(q);
523 	}
524 	return;
525 
526 discard:
527 	freemsg(mp);
528 }
529 
530 /*
531  * M_DATA srv
532  */
533 static void
534 str_mdata_srv(dld_str_t *dsp, mblk_t *mp)
535 {
536 	queue_t		*q = dsp->ds_wq;
537 
538 	/*
539 	 * Attempt to transmit the packet.
540 	 */
541 	if ((mp = dls_tx(dsp->ds_dc, mp)) == NULL)
542 		return;
543 
544 	(void) str_putbq(q, mp);
545 	qenable(q);
546 }
547 
548 /*
549  * M_PROTO put
550  */
551 static void
552 str_mproto_put(dld_str_t *dsp, mblk_t *mp)
553 {
554 	dld_proto(dsp, mp);
555 }
556 
557 /*
558  * M_PCPROTO put
559  */
560 static void
561 str_mpcproto_put(dld_str_t *dsp, mblk_t *mp)
562 {
563 	dld_proto(dsp, mp);
564 }
565 
566 /*
567  * M_IOCTL put
568  */
569 static void
570 str_mioctl_put(dld_str_t *dsp, mblk_t *mp)
571 {
572 	dld_ioc(dsp, mp);
573 }
574 
575 /*
576  * M_FLUSH put
577  */
578 /*ARGSUSED*/
579 static void
580 str_mflush_put(dld_str_t *dsp, mblk_t *mp)
581 {
582 	queue_t		*q = dsp->ds_wq;
583 
584 	if (*mp->b_rptr & FLUSHW) {
585 		flushq(q, FLUSHALL);
586 		*mp->b_rptr &= ~FLUSHW;
587 	}
588 
589 	if (*mp->b_rptr & FLUSHR)
590 		qreply(q, mp);
591 	else
592 		freemsg(mp);
593 }
594 
595 /*
596  * M_* put.
597  */
598 /*ARGSUSED*/
599 static void
600 str_m_put(dld_str_t *dsp, mblk_t *mp)
601 {
602 	freemsg(mp);
603 }
604 
605 /*
606  * M_* put.
607  */
608 /*ARGSUSED*/
609 static void
610 str_m_srv(dld_str_t *dsp, mblk_t *mp)
611 {
612 	freemsgchain(mp);
613 }
614 
615 /*
616  * Process DL_ATTACH_REQ (style 2) or open(2) (style 1).
617  */
618 int
619 dld_str_attach(dld_str_t *dsp, dld_ppa_t *dpp)
620 {
621 	int			err;
622 	dls_channel_t		dc;
623 	uint_t			addr_length;
624 
625 	ASSERT(dsp->ds_dc == NULL);
626 
627 	/*
628 	 * Open a channel.
629 	 */
630 	if ((err = dls_open(dpp->dp_name, &dc)) != 0)
631 		return (err);
632 
633 	/*
634 	 * Cache the MAC interface handle, a pointer to the immutable MAC
635 	 * information and the current and 'factory' MAC address.
636 	 */
637 	dsp->ds_mh = dls_mac(dc);
638 	dsp->ds_mip = mac_info(dsp->ds_mh);
639 
640 	mac_unicst_get(dsp->ds_mh, dsp->ds_curr_addr);
641 
642 	addr_length = dsp->ds_mip->mi_addr_length;
643 	bcopy(dsp->ds_mip->mi_unicst_addr, dsp->ds_fact_addr, addr_length);
644 
645 	/*
646 	 * Cache the interface VLAN identifier. (This will be VLAN_ID_NONE for
647 	 * a non-VLAN interface).
648 	 */
649 	dsp->ds_vid = dls_vid(dc);
650 
651 	/*
652 	 * Set the default packet priority.
653 	 */
654 	dsp->ds_pri = 0;
655 
656 	/*
657 	 * Add a notify function so that the we get updates from the MAC.
658 	 */
659 	dsp->ds_mnh = mac_notify_add(dsp->ds_mh, str_notify, (void *)dsp);
660 
661 	dsp->ds_dc = dc;
662 	return (0);
663 }
664 
665 /*
666  * Process DL_DETACH_REQ (style 2) or close(2) (style 1). Can also be called
667  * from close(2) for style 2.
668  */
669 void
670 dld_str_detach(dld_str_t *dsp)
671 {
672 	/*
673 	 * Remove the notify function.
674 	 */
675 	mac_notify_remove(dsp->ds_mh, dsp->ds_mnh);
676 
677 	/*
678 	 * Make sure the M_DATA handler is reset.
679 	 */
680 	dld_str_tx_drop(dsp);
681 
682 	/*
683 	 * Clear the polling and promisc flags.
684 	 */
685 	dsp->ds_polling = B_FALSE;
686 	dsp->ds_promisc = 0;
687 
688 	/*
689 	 * Close the channel.
690 	 */
691 	dls_close(dsp->ds_dc);
692 	dsp->ds_dc = NULL;
693 	dsp->ds_mh = NULL;
694 }
695 
696 /*
697  * Enable raw mode for this stream. This mode is mutually exclusive with
698  * fast-path and/or polling.
699  */
700 void
701 dld_str_tx_raw(dld_str_t *dsp)
702 {
703 	/*
704 	 * Enable M_DATA message handling.
705 	 */
706 	dsp->ds_mi[M_DATA].smi_put = str_mdata_raw_put;
707 	dsp->ds_mi[M_DATA].smi_srv = str_mdata_srv;
708 }
709 
710 /*
711  * Enable fast-path for this stream.
712  */
713 void
714 dld_str_tx_fastpath(dld_str_t *dsp)
715 {
716 	/*
717 	 * Enable M_DATA message handling.
718 	 */
719 	dsp->ds_mi[M_DATA].smi_put = str_mdata_fastpath_put;
720 	dsp->ds_mi[M_DATA].smi_srv = str_mdata_srv;
721 }
722 
723 /*
724  * Disable fast-path or raw mode.
725  */
726 void
727 dld_str_tx_drop(dld_str_t *dsp)
728 {
729 	/*
730 	 * Disable M_DATA message handling.
731 	 */
732 	dsp->ds_mi[M_DATA].smi_put = str_m_put;
733 	dsp->ds_mi[M_DATA].smi_srv = str_m_srv;
734 }
735 
736 /*
737  * Raw mode receive function.
738  */
739 /*ARGSUSED*/
740 void
741 dld_str_rx_raw(void *arg, mac_resource_handle_t mrh, mblk_t *mp,
742     size_t header_length)
743 {
744 	dld_str_t		*dsp = (dld_str_t *)arg;
745 	mblk_t			*next;
746 
747 	ASSERT(mp != NULL);
748 	do {
749 		/*
750 		 * Get the pointer to the next packet in the chain and then
751 		 * clear b_next before the packet gets passed on.
752 		 */
753 		next = mp->b_next;
754 		mp->b_next = NULL;
755 
756 		/*
757 		 * Wind back b_rptr to point at the MAC header.
758 		 */
759 		ASSERT(mp->b_rptr >= DB_BASE(mp) + header_length);
760 		mp->b_rptr -= header_length;
761 		if (header_length == sizeof (struct ether_vlan_header)) {
762 			/*
763 			 * Strip off the vtag
764 			 */
765 			ovbcopy(mp->b_rptr, mp->b_rptr + VLAN_TAGSZ,
766 			    2 * ETHERADDRL);
767 			mp->b_rptr += VLAN_TAGSZ;
768 		}
769 
770 		/*
771 		 * Pass the packet on.
772 		 */
773 		putnext(dsp->ds_rq, mp);
774 
775 		/*
776 		 * Move on to the next packet in the chain.
777 		 */
778 		mp = next;
779 	} while (mp != NULL);
780 }
781 
782 /*
783  * Fast-path receive function.
784  */
785 /*ARGSUSED*/
786 void
787 dld_str_rx_fastpath(void *arg, mac_resource_handle_t mrh, mblk_t *mp,
788     size_t header_length)
789 {
790 	dld_str_t		*dsp = (dld_str_t *)arg;
791 	mblk_t			*next;
792 
793 	ASSERT(mp != NULL);
794 	do {
795 		/*
796 		 * Get the pointer to the next packet in the chain and then
797 		 * clear b_next before the packet gets passed on.
798 		 */
799 		next = mp->b_next;
800 		mp->b_next = NULL;
801 
802 		/*
803 		 * Pass the packet on.
804 		 */
805 		putnext(dsp->ds_rq, mp);
806 
807 		/*
808 		 * Move on to the next packet in the chain.
809 		 */
810 		mp = next;
811 	} while (mp != NULL);
812 }
813 
814 /*
815  * Default receive function (send DL_UNITDATA_IND messages).
816  */
817 /*ARGSUSED*/
818 void
819 dld_str_rx_unitdata(void *arg, mac_resource_handle_t mrh, mblk_t *mp,
820     size_t header_length)
821 {
822 	dld_str_t		*dsp = (dld_str_t *)arg;
823 	mblk_t			*ud_mp;
824 	mblk_t			*next;
825 
826 	ASSERT(mp != NULL);
827 	do {
828 		/*
829 		 * Get the pointer to the next packet in the chain and then
830 		 * clear b_next before the packet gets passed on.
831 		 */
832 		next = mp->b_next;
833 		mp->b_next = NULL;
834 
835 		/*
836 		 * Wind back b_rptr to point at the MAC header.
837 		 */
838 		ASSERT(mp->b_rptr >= DB_BASE(mp) + header_length);
839 		mp->b_rptr -= header_length;
840 
841 		/*
842 		 * Create the DL_UNITDATA_IND M_PROTO.
843 		 */
844 		if ((ud_mp = str_unitdata_ind(dsp, mp)) == NULL) {
845 			freemsgchain(mp);
846 			return;
847 		}
848 
849 		/*
850 		 * Advance b_rptr to point at the payload again.
851 		 */
852 		mp->b_rptr += header_length;
853 
854 		/*
855 		 * Prepend the DL_UNITDATA_IND.
856 		 */
857 		ud_mp->b_cont = mp;
858 
859 		/*
860 		 * Send the message.
861 		 */
862 		putnext(dsp->ds_rq, ud_mp);
863 
864 		/*
865 		 * Move on to the next packet in the chain.
866 		 */
867 		mp = next;
868 	} while (mp != NULL);
869 }
870 
871 /*
872  * Generate DL_NOTIFY_IND messages to notify the DLPI consumer of the
873  * current state of the interface.
874  */
875 void
876 dld_str_notify_ind(dld_str_t *dsp)
877 {
878 	mac_notify_type_t	type;
879 
880 	for (type = 0; type < MAC_NNOTE; type++)
881 		str_notify(dsp, type);
882 }
883 
884 typedef struct dl_unitdata_ind_wrapper {
885 	dl_unitdata_ind_t	dl_unitdata;
886 	uint8_t			dl_dest_addr[MAXADDRLEN + sizeof (uint16_t)];
887 	uint8_t			dl_src_addr[MAXADDRLEN + sizeof (uint16_t)];
888 } dl_unitdata_ind_wrapper_t;
889 
890 /*
891  * Create a DL_UNITDATA_IND M_PROTO message.
892  */
893 static mblk_t *
894 str_unitdata_ind(dld_str_t *dsp, mblk_t *mp)
895 {
896 	mblk_t				*nmp;
897 	dl_unitdata_ind_wrapper_t	*dlwp;
898 	dl_unitdata_ind_t		*dlp;
899 	dls_header_info_t		dhi;
900 	uint_t				addr_length;
901 	uint8_t				*daddr;
902 	uint8_t				*saddr;
903 
904 	/*
905 	 * Get the packet header information.
906 	 */
907 	dls_header_info(dsp->ds_dc, mp, &dhi);
908 
909 	/*
910 	 * Allocate a message large enough to contain the wrapper structure
911 	 * defined above.
912 	 */
913 	if ((nmp = mexchange(dsp->ds_wq, NULL,
914 	    sizeof (dl_unitdata_ind_wrapper_t), M_PROTO,
915 	    DL_UNITDATA_IND)) == NULL)
916 		return (NULL);
917 
918 	dlwp = (dl_unitdata_ind_wrapper_t *)nmp->b_rptr;
919 
920 	dlp = &(dlwp->dl_unitdata);
921 	ASSERT(dlp == (dl_unitdata_ind_t *)nmp->b_rptr);
922 	ASSERT(dlp->dl_primitive == DL_UNITDATA_IND);
923 
924 	/*
925 	 * Copy in the destination address.
926 	 */
927 	addr_length = dsp->ds_mip->mi_addr_length;
928 	daddr = dlwp->dl_dest_addr;
929 	dlp->dl_dest_addr_offset = (uintptr_t)daddr - (uintptr_t)dlp;
930 	bcopy(dhi.dhi_daddr, daddr, addr_length);
931 
932 	/*
933 	 * Set the destination DLSAP to our bound DLSAP value.
934 	 */
935 	*(uint16_t *)(daddr + addr_length) = dsp->ds_sap;
936 	dlp->dl_dest_addr_length = addr_length + sizeof (uint16_t);
937 
938 	/*
939 	 * If the destination address was a group address then
940 	 * dl_group_address field should be non-zero.
941 	 */
942 	dlp->dl_group_address = dhi.dhi_isgroup;
943 
944 	/*
945 	 * Copy in the source address.
946 	 */
947 	saddr = dlwp->dl_src_addr;
948 	dlp->dl_src_addr_offset = (uintptr_t)saddr - (uintptr_t)dlp;
949 	bcopy(dhi.dhi_saddr, saddr, addr_length);
950 
951 	/*
952 	 * Set the source DLSAP to the packet ethertype.
953 	 */
954 	*(uint16_t *)(saddr + addr_length) = dhi.dhi_ethertype;
955 	dlp->dl_src_addr_length = addr_length + sizeof (uint16_t);
956 
957 	return (nmp);
958 }
959 
960 /*
961  * DL_NOTIFY_IND: DL_NOTE_PROMISC_ON_PHYS
962  */
963 static void
964 str_notify_promisc_on_phys(dld_str_t *dsp)
965 {
966 	mblk_t		*mp;
967 	dl_notify_ind_t	*dlip;
968 
969 	if (!(dsp->ds_notifications & DL_NOTE_PROMISC_ON_PHYS))
970 		return;
971 
972 	if ((mp = mexchange(dsp->ds_wq, NULL, sizeof (dl_notify_ind_t),
973 	    M_PROTO, 0)) == NULL)
974 		return;
975 
976 	bzero(mp->b_rptr, sizeof (dl_notify_ind_t));
977 	dlip = (dl_notify_ind_t *)mp->b_rptr;
978 	dlip->dl_primitive = DL_NOTIFY_IND;
979 	dlip->dl_notification = DL_NOTE_PROMISC_ON_PHYS;
980 
981 	qreply(dsp->ds_wq, mp);
982 }
983 
984 /*
985  * DL_NOTIFY_IND: DL_NOTE_PROMISC_OFF_PHYS
986  */
987 static void
988 str_notify_promisc_off_phys(dld_str_t *dsp)
989 {
990 	mblk_t		*mp;
991 	dl_notify_ind_t	*dlip;
992 
993 	if (!(dsp->ds_notifications & DL_NOTE_PROMISC_OFF_PHYS))
994 		return;
995 
996 	if ((mp = mexchange(dsp->ds_wq, NULL, sizeof (dl_notify_ind_t),
997 	    M_PROTO, 0)) == NULL)
998 		return;
999 
1000 	bzero(mp->b_rptr, sizeof (dl_notify_ind_t));
1001 	dlip = (dl_notify_ind_t *)mp->b_rptr;
1002 	dlip->dl_primitive = DL_NOTIFY_IND;
1003 	dlip->dl_notification = DL_NOTE_PROMISC_OFF_PHYS;
1004 
1005 	qreply(dsp->ds_wq, mp);
1006 }
1007 
1008 /*
1009  * DL_NOTIFY_IND: DL_NOTE_PHYS_ADDR
1010  */
1011 static void
1012 str_notify_phys_addr(dld_str_t *dsp, const uint8_t *addr)
1013 {
1014 	mblk_t		*mp;
1015 	dl_notify_ind_t	*dlip;
1016 	uint_t		addr_length;
1017 	uint16_t	ethertype;
1018 
1019 	if (!(dsp->ds_notifications & DL_NOTE_PHYS_ADDR))
1020 		return;
1021 
1022 	addr_length = dsp->ds_mip->mi_addr_length;
1023 	if ((mp = mexchange(dsp->ds_wq, NULL,
1024 	    sizeof (dl_notify_ind_t) + addr_length + sizeof (uint16_t),
1025 	    M_PROTO, 0)) == NULL)
1026 		return;
1027 
1028 	bzero(mp->b_rptr, sizeof (dl_notify_ind_t));
1029 	dlip = (dl_notify_ind_t *)mp->b_rptr;
1030 	dlip->dl_primitive = DL_NOTIFY_IND;
1031 	dlip->dl_notification = DL_NOTE_PHYS_ADDR;
1032 	dlip->dl_data = DL_CURR_PHYS_ADDR;
1033 	dlip->dl_addr_offset = sizeof (dl_notify_ind_t);
1034 	dlip->dl_addr_length = addr_length + sizeof (uint16_t);
1035 
1036 	bcopy(addr, &dlip[1], addr_length);
1037 
1038 	ethertype = (dsp->ds_sap < ETHERTYPE_802_MIN) ? 0 : dsp->ds_sap;
1039 	*(uint16_t *)((uchar_t *)(dlip + 1) + addr_length) =
1040 		ethertype;
1041 
1042 	qreply(dsp->ds_wq, mp);
1043 }
1044 
1045 /*
1046  * DL_NOTIFY_IND: DL_NOTE_LINK_UP
1047  */
1048 static void
1049 str_notify_link_up(dld_str_t *dsp)
1050 {
1051 	mblk_t		*mp;
1052 	dl_notify_ind_t	*dlip;
1053 
1054 	if (!(dsp->ds_notifications & DL_NOTE_LINK_UP))
1055 		return;
1056 
1057 	if ((mp = mexchange(dsp->ds_wq, NULL, sizeof (dl_notify_ind_t),
1058 	    M_PROTO, 0)) == NULL)
1059 		return;
1060 
1061 	bzero(mp->b_rptr, sizeof (dl_notify_ind_t));
1062 	dlip = (dl_notify_ind_t *)mp->b_rptr;
1063 	dlip->dl_primitive = DL_NOTIFY_IND;
1064 	dlip->dl_notification = DL_NOTE_LINK_UP;
1065 
1066 	qreply(dsp->ds_wq, mp);
1067 }
1068 
1069 /*
1070  * DL_NOTIFY_IND: DL_NOTE_LINK_DOWN
1071  */
1072 static void
1073 str_notify_link_down(dld_str_t *dsp)
1074 {
1075 	mblk_t		*mp;
1076 	dl_notify_ind_t	*dlip;
1077 
1078 	if (!(dsp->ds_notifications & DL_NOTE_LINK_DOWN))
1079 		return;
1080 
1081 	if ((mp = mexchange(dsp->ds_wq, NULL, sizeof (dl_notify_ind_t),
1082 	    M_PROTO, 0)) == NULL)
1083 		return;
1084 
1085 	bzero(mp->b_rptr, sizeof (dl_notify_ind_t));
1086 	dlip = (dl_notify_ind_t *)mp->b_rptr;
1087 	dlip->dl_primitive = DL_NOTIFY_IND;
1088 	dlip->dl_notification = DL_NOTE_LINK_DOWN;
1089 
1090 	qreply(dsp->ds_wq, mp);
1091 }
1092 
1093 /*
1094  * DL_NOTIFY_IND: DL_NOTE_SPEED
1095  */
1096 static void
1097 str_notify_speed(dld_str_t *dsp, uint32_t speed)
1098 {
1099 	mblk_t		*mp;
1100 	dl_notify_ind_t	*dlip;
1101 
1102 	if (!(dsp->ds_notifications & DL_NOTE_SPEED))
1103 		return;
1104 
1105 	if ((mp = mexchange(dsp->ds_wq, NULL, sizeof (dl_notify_ind_t),
1106 	    M_PROTO, 0)) == NULL)
1107 		return;
1108 
1109 	bzero(mp->b_rptr, sizeof (dl_notify_ind_t));
1110 	dlip = (dl_notify_ind_t *)mp->b_rptr;
1111 	dlip->dl_primitive = DL_NOTIFY_IND;
1112 	dlip->dl_notification = DL_NOTE_SPEED;
1113 	dlip->dl_data = speed;
1114 
1115 	qreply(dsp->ds_wq, mp);
1116 }
1117 
1118 /*
1119  * DL_NOTIFY_IND: DL_NOTE_CAPAB_RENEG
1120  */
1121 static void
1122 str_notify_capab_reneg(dld_str_t *dsp)
1123 {
1124 	mblk_t		*mp;
1125 	dl_notify_ind_t	*dlip;
1126 
1127 	if (!(dsp->ds_notifications & DL_NOTE_CAPAB_RENEG))
1128 		return;
1129 
1130 	if ((mp = mexchange(dsp->ds_wq, NULL, sizeof (dl_notify_ind_t),
1131 	    M_PROTO, 0)) == NULL)
1132 		return;
1133 
1134 	bzero(mp->b_rptr, sizeof (dl_notify_ind_t));
1135 	dlip = (dl_notify_ind_t *)mp->b_rptr;
1136 	dlip->dl_primitive = DL_NOTIFY_IND;
1137 	dlip->dl_notification = DL_NOTE_CAPAB_RENEG;
1138 
1139 	qreply(dsp->ds_wq, mp);
1140 }
1141 
1142 /*
1143  * MAC notification callback.
1144  */
1145 static void
1146 str_notify(void *arg, mac_notify_type_t type)
1147 {
1148 	dld_str_t		*dsp = (dld_str_t *)arg;
1149 	queue_t			*q = dsp->ds_wq;
1150 
1151 	switch (type) {
1152 	case MAC_NOTE_TX:
1153 		enableok(q);
1154 		qenable(q);
1155 		break;
1156 
1157 	case MAC_NOTE_DEVPROMISC:
1158 		/*
1159 		 * Send the appropriate DL_NOTIFY_IND.
1160 		 */
1161 		if (mac_promisc_get(dsp->ds_mh, MAC_DEVPROMISC))
1162 			str_notify_promisc_on_phys(dsp);
1163 		else
1164 			str_notify_promisc_off_phys(dsp);
1165 		break;
1166 
1167 	case MAC_NOTE_PROMISC:
1168 		break;
1169 
1170 	case MAC_NOTE_UNICST:
1171 		/*
1172 		 * This notification is sent whenever the MAC unicast address
1173 		 * changes. We need to re-cache the address.
1174 		 */
1175 		mac_unicst_get(dsp->ds_mh, dsp->ds_curr_addr);
1176 
1177 		/*
1178 		 * Send the appropriate DL_NOTIFY_IND.
1179 		 */
1180 		str_notify_phys_addr(dsp, dsp->ds_curr_addr);
1181 		break;
1182 
1183 	case MAC_NOTE_LINK:
1184 		/*
1185 		 * This notification is sent every time the MAC driver
1186 		 * updates the link state.
1187 		 */
1188 		switch (mac_link_get(dsp->ds_mh)) {
1189 		case LINK_STATE_UP:
1190 			/*
1191 			 * The link is up so send the appropriate
1192 			 * DL_NOTIFY_IND.
1193 			 */
1194 			str_notify_link_up(dsp);
1195 
1196 			/*
1197 			 * If we can find the link speed then send a
1198 			 * DL_NOTIFY_IND for that too.
1199 			 */
1200 			if (dsp->ds_mip->mi_stat[MAC_STAT_IFSPEED]) {
1201 				uint64_t	val;
1202 
1203 				val = mac_stat_get(dsp->ds_mh,
1204 				    MAC_STAT_IFSPEED);
1205 				str_notify_speed(dsp,
1206 				    (uint32_t)(val / 1000ull));
1207 			}
1208 			break;
1209 
1210 		case LINK_STATE_DOWN:
1211 			/*
1212 			 * The link is down so send the appropriate
1213 			 * DL_NOTIFY_IND.
1214 			 */
1215 			str_notify_link_down(dsp);
1216 			break;
1217 
1218 		default:
1219 			break;
1220 		}
1221 		break;
1222 
1223 	case MAC_NOTE_RESOURCE:
1224 		/*
1225 		 * This notification is sent whenever the MAC resources
1226 		 * change. We need to renegotiate the capabilities.
1227 		 * Send the appropriate DL_NOTIFY_IND.
1228 		 */
1229 		str_notify_capab_reneg(dsp);
1230 		break;
1231 
1232 	default:
1233 		ASSERT(B_FALSE);
1234 		break;
1235 	}
1236 }
1237 
1238 /*
1239  * Put a chain of packets back on the queue.
1240  */
1241 static void
1242 str_putbq(queue_t *q, mblk_t *mp)
1243 {
1244 	mblk_t	*bp = NULL;
1245 	mblk_t	*nextp;
1246 
1247 	/*
1248 	 * Reverse the order of the chain.
1249 	 */
1250 	while (mp != NULL) {
1251 		nextp = mp->b_next;
1252 
1253 		mp->b_next = bp;
1254 		bp = mp;
1255 
1256 		mp = nextp;
1257 	}
1258 
1259 	/*
1260 	 * Walk the reversed chain and put each message back on the
1261 	 * queue.
1262 	 */
1263 	while (bp != NULL) {
1264 		nextp = bp->b_next;
1265 		bp->b_next = NULL;
1266 
1267 		(void) putbq(q, bp);
1268 
1269 		bp = nextp;
1270 	}
1271 }
1272