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