xref: /titanic_44/usr/src/uts/common/io/dls/dls.c (revision a6e6969cf9cfe2070eae4cd6071f76b0fa4f539f)
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 (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 /*
29  * Data-Link Services Module
30  */
31 
32 #include	<sys/types.h>
33 #include	<sys/stream.h>
34 #include	<sys/strsun.h>
35 #include	<sys/sysmacros.h>
36 #include	<sys/atomic.h>
37 #include	<sys/stat.h>
38 #include	<sys/dlpi.h>
39 #include	<sys/vlan.h>
40 #include	<sys/ethernet.h>
41 #include	<sys/byteorder.h>
42 #include	<sys/mac.h>
43 
44 #include	<sys/dls.h>
45 #include	<sys/dls_impl.h>
46 #include	<sys/dls_soft_ring.h>
47 
48 static kmem_cache_t	*i_dls_impl_cachep;
49 static uint32_t		i_dls_impl_count;
50 
51 static kstat_t	*dls_ksp = (kstat_t *)NULL;
52 struct dls_kstats dls_kstat =
53 {
54 	{ "soft_ring_pkt_drop", KSTAT_DATA_UINT32 },
55 };
56 
57 static int dls_open(dls_vlan_t *, dls_dl_handle_t ddh, dls_channel_t *);
58 
59 /*
60  * Private functions.
61  */
62 
63 /*ARGSUSED*/
64 static int
65 i_dls_constructor(void *buf, void *arg, int kmflag)
66 {
67 	dls_impl_t	*dip = buf;
68 
69 	bzero(buf, sizeof (dls_impl_t));
70 
71 	rw_init(&(dip->di_lock), NULL, RW_DRIVER, NULL);
72 	return (0);
73 }
74 
75 /*ARGSUSED*/
76 static void
77 i_dls_destructor(void *buf, void *arg)
78 {
79 	dls_impl_t	*dip = buf;
80 
81 	ASSERT(dip->di_dvp == NULL);
82 	ASSERT(dip->di_mnh == NULL);
83 	ASSERT(dip->di_dmap == NULL);
84 	ASSERT(!dip->di_local);
85 	ASSERT(!dip->di_bound);
86 	ASSERT(dip->di_rx == NULL);
87 	ASSERT(dip->di_txinfo == NULL);
88 
89 	rw_destroy(&(dip->di_lock));
90 }
91 
92 static void
93 i_dls_notify(void *arg, mac_notify_type_t type)
94 {
95 	dls_impl_t		*dip = arg;
96 
97 	switch (type) {
98 	case MAC_NOTE_UNICST:
99 		mac_unicst_get(dip->di_mh, dip->di_unicst_addr);
100 		break;
101 
102 	case MAC_NOTE_PROMISC:
103 	case MAC_NOTE_VNIC:
104 		/*
105 		 * Every time the MAC interface changes promiscuity or
106 		 * the VNIC characteristics change we need to reset
107 		 * our transmit information.
108 		 */
109 		dip->di_txinfo = mac_tx_get(dip->di_mh);
110 		break;
111 	}
112 }
113 
114 static void
115 dls_stat_init()
116 {
117 	if ((dls_ksp = kstat_create("dls", 0, "dls_stat",
118 	    "net", KSTAT_TYPE_NAMED,
119 	    sizeof (dls_kstat) / sizeof (kstat_named_t),
120 	    KSTAT_FLAG_VIRTUAL)) == NULL) {
121 		cmn_err(CE_WARN,
122 		"DLS: failed to create kstat structure for dls stats");
123 		return;
124 	}
125 	dls_ksp->ks_data = (void *)&dls_kstat;
126 	kstat_install(dls_ksp);
127 }
128 
129 static void
130 dls_stat_destroy()
131 {
132 	kstat_delete(dls_ksp);
133 }
134 
135 /*
136  * Module initialization functions.
137  */
138 
139 void
140 dls_init(void)
141 {
142 	/*
143 	 * Create a kmem_cache of dls_impl_t.
144 	 */
145 	i_dls_impl_cachep = kmem_cache_create("dls_cache",
146 	    sizeof (dls_impl_t), 0, i_dls_constructor, i_dls_destructor, NULL,
147 	    NULL, NULL, 0);
148 	ASSERT(i_dls_impl_cachep != NULL);
149 	soft_ring_init();
150 	dls_stat_init();
151 }
152 
153 int
154 dls_fini(void)
155 {
156 	/*
157 	 * If there are any dls_impl_t in use then return EBUSY.
158 	 */
159 	if (i_dls_impl_count != 0)
160 		return (EBUSY);
161 
162 	/*
163 	 * Destroy the kmem_cache.
164 	 */
165 	kmem_cache_destroy(i_dls_impl_cachep);
166 	dls_stat_destroy();
167 	return (0);
168 }
169 
170 /*
171  * Client functions.
172  */
173 
174 /*
175  * /dev node style-2 VLAN PPA access. This might result in a newly created
176  * dls_vlan_t. Note that this dls_vlan_t is different from others, in that
177  * this VLAN might not have a link name that is managed by dlmgmtd (we cannot
178  * use its VLAN ppa hack name as it might conflict with a vanity name).
179  */
180 int
181 dls_open_style2_vlan(major_t major, uint_t ppa, dls_channel_t *dcp)
182 {
183 	dev_t		dev = makedevice(major, DLS_PPA2INST(ppa) + 1);
184 	uint_t		vid = DLS_PPA2VID(ppa);
185 	dls_vlan_t	*lndvp, *dvp;
186 	int		err;
187 
188 	/*
189 	 * First find the dls_vlan_t this VLAN is created on. This must be
190 	 * a GLDv3 driver based device.
191 	 */
192 	if ((err = dls_vlan_hold_by_dev(dev, &lndvp)) != 0)
193 		return (err);
194 
195 	if (vid > VLAN_ID_MAX)
196 		return (ENOENT);
197 
198 	err = dls_vlan_hold(lndvp->dv_dlp->dl_name, vid, &dvp, B_FALSE, B_TRUE);
199 	if (err != 0)
200 		goto done;
201 
202 	if ((err = dls_open(dvp, NULL, dcp)) != 0)
203 		dls_vlan_rele(dvp);
204 
205 done:
206 	dls_vlan_rele(lndvp);
207 	return (err);
208 }
209 
210 int
211 dls_open_by_dev(dev_t dev, dls_channel_t *dcp)
212 {
213 	dls_dl_handle_t	ddh;
214 	dls_vlan_t	*dvp;
215 	int		err;
216 
217 	/*
218 	 * Get a reference to the given dls_vlan_t.
219 	 */
220 	if ((err = dls_devnet_open_by_dev(dev, &dvp, &ddh)) != 0)
221 		return (err);
222 
223 	if ((err = dls_open(dvp, ddh, dcp)) != 0) {
224 		if (ddh != NULL)
225 			dls_devnet_close(ddh);
226 		else
227 			dls_vlan_rele(dvp);
228 	}
229 
230 	return (err);
231 }
232 
233 static int
234 dls_open(dls_vlan_t *dvp, dls_dl_handle_t ddh, dls_channel_t *dcp)
235 {
236 	dls_impl_t	*dip;
237 	dls_link_t	*dlp;
238 	int		err;
239 	zoneid_t	zid = getzoneid();
240 	boolean_t	local;
241 
242 	/*
243 	 * Check whether this client belongs to the zone of this dvp. Note that
244 	 * a global zone client is allowed to open a local zone dvp.
245 	 */
246 	mutex_enter(&dvp->dv_lock);
247 	if (zid != GLOBAL_ZONEID && dvp->dv_zid != zid) {
248 		mutex_exit(&dvp->dv_lock);
249 		return (ENOENT);
250 	}
251 	local = (zid == dvp->dv_zid);
252 	dvp->dv_zone_ref += (local ? 1 : 0);
253 	mutex_exit(&dvp->dv_lock);
254 
255 	dlp = dvp->dv_dlp;
256 	if ((err = mac_start(dlp->dl_mh)) != 0) {
257 		mutex_enter(&dvp->dv_lock);
258 		dvp->dv_zone_ref -= (local ? 1 : 0);
259 		mutex_exit(&dvp->dv_lock);
260 		return (err);
261 	}
262 
263 	/*
264 	 * Allocate a new dls_impl_t.
265 	 */
266 	dip = kmem_cache_alloc(i_dls_impl_cachep, KM_SLEEP);
267 	dip->di_dvp = dvp;
268 	dip->di_ddh = ddh;
269 
270 	/*
271 	 * Cache a copy of the MAC interface handle, a pointer to the
272 	 * immutable MAC info and a copy of the current MAC address.
273 	 */
274 	dip->di_mh = dlp->dl_mh;
275 	dip->di_mip = dlp->dl_mip;
276 
277 	mac_unicst_get(dip->di_mh, dip->di_unicst_addr);
278 
279 	/*
280 	 * Set the MAC transmit information.
281 	 */
282 	dip->di_txinfo = mac_tx_get(dip->di_mh);
283 
284 	/*
285 	 * Add a notification function so that we get updates from
286 	 * the MAC.
287 	 */
288 	dip->di_mnh = mac_notify_add(dip->di_mh, i_dls_notify,
289 	    (void *)dip);
290 
291 	/*
292 	 * Bump the kmem_cache count to make sure it is not prematurely
293 	 * destroyed.
294 	 */
295 	atomic_add_32(&i_dls_impl_count, 1);
296 
297 	dip->di_local = local;
298 
299 	/*
300 	 * Hand back a reference to the dls_impl_t.
301 	 */
302 	*dcp = (dls_channel_t)dip;
303 	return (0);
304 }
305 
306 void
307 dls_close(dls_channel_t dc)
308 {
309 	dls_impl_t		*dip = (dls_impl_t *)dc;
310 	dls_vlan_t		*dvp = dip->di_dvp;
311 	dls_link_t		*dlp = dvp->dv_dlp;
312 	dls_multicst_addr_t	*p;
313 	dls_multicst_addr_t	*nextp;
314 	dls_dl_handle_t		ddh = dip->di_ddh;
315 
316 	if (dip->di_local) {
317 		mutex_enter(&dvp->dv_lock);
318 		dvp->dv_zone_ref--;
319 		mutex_exit(&dvp->dv_lock);
320 	}
321 	dip->di_local = B_FALSE;
322 
323 	dls_active_clear(dc);
324 
325 	rw_enter(&(dip->di_lock), RW_WRITER);
326 	/*
327 	 * Remove the notify function.
328 	 */
329 	mac_notify_remove(dip->di_mh, dip->di_mnh);
330 	dip->di_mnh = NULL;
331 
332 	/*
333 	 * If the dls_impl_t is bound then unbind it.
334 	 */
335 	if (dip->di_bound) {
336 		rw_exit(&(dip->di_lock));
337 		dls_link_remove(dlp, dip);
338 		rw_enter(&(dip->di_lock), RW_WRITER);
339 		dip->di_bound = B_FALSE;
340 	}
341 
342 	/*
343 	 * Walk the list of multicast addresses, disabling each at
344 	 * the MAC.
345 	 */
346 	for (p = dip->di_dmap; p != NULL; p = nextp) {
347 		(void) mac_multicst_remove(dip->di_mh, p->dma_addr);
348 		nextp = p->dma_nextp;
349 		kmem_free(p, sizeof (dls_multicst_addr_t));
350 	}
351 	dip->di_dmap = NULL;
352 
353 	dip->di_rx = NULL;
354 	dip->di_rx_arg = NULL;
355 	rw_exit(&(dip->di_lock));
356 
357 	/*
358 	 * If the MAC has been set in promiscuous mode then disable it.
359 	 */
360 	(void) dls_promisc(dc, 0);
361 	dip->di_txinfo = NULL;
362 
363 	/*
364 	 * Free the dls_impl_t back to the cache.
365 	 */
366 	dip->di_txinfo = NULL;
367 
368 	if (dip->di_soft_ring_list != NULL) {
369 		soft_ring_set_destroy(dip->di_soft_ring_list,
370 		    dip->di_soft_ring_size);
371 		dip->di_soft_ring_list = NULL;
372 	}
373 	dip->di_soft_ring_size = 0;
374 
375 	/*
376 	 * Decrement the reference count to allow the cache to be destroyed
377 	 * if there are no more dls_impl_t.
378 	 */
379 	atomic_add_32(&i_dls_impl_count, -1);
380 
381 	dip->di_dvp = NULL;
382 
383 	kmem_cache_free(i_dls_impl_cachep, dip);
384 
385 	mac_stop(dvp->dv_dlp->dl_mh);
386 
387 	/*
388 	 * Release our reference to the dls_vlan_t allowing that to be
389 	 * destroyed if there are no more dls_impl_t. An unreferenced tagged
390 	 * (non-persistent) vlan gets destroyed automatically.
391 	 */
392 	if (ddh != NULL)
393 		dls_devnet_close(ddh);
394 	else
395 		dls_vlan_rele(dvp);
396 }
397 
398 mac_handle_t
399 dls_mac(dls_channel_t dc)
400 {
401 	return (((dls_impl_t *)dc)->di_mh);
402 }
403 
404 uint16_t
405 dls_vid(dls_channel_t dc)
406 {
407 	return (((dls_impl_t *)dc)->di_dvp->dv_id);
408 }
409 
410 int
411 dls_bind(dls_channel_t dc, uint32_t sap)
412 {
413 	dls_impl_t	*dip = (dls_impl_t *)dc;
414 	dls_link_t	*dlp;
415 	uint32_t	dls_sap;
416 
417 	/*
418 	 * Check to see the value is legal for the media type.
419 	 */
420 	if (!mac_sap_verify(dip->di_mh, sap, &dls_sap))
421 		return (EINVAL);
422 	if (dip->di_promisc & DLS_PROMISC_SAP)
423 		dls_sap = DLS_SAP_PROMISC;
424 
425 	/*
426 	 * Set up the dls_impl_t to mark it as able to receive packets.
427 	 */
428 	rw_enter(&(dip->di_lock), RW_WRITER);
429 	ASSERT(!dip->di_bound);
430 	dip->di_sap = sap;
431 	dip->di_bound = B_TRUE;
432 	rw_exit(&(dip->di_lock));
433 
434 	/*
435 	 * Now bind the dls_impl_t by adding it into the hash table in the
436 	 * dls_link_t.
437 	 *
438 	 * NOTE: This must be done without the dls_impl_t lock being held
439 	 *	 otherwise deadlock may ensue.
440 	 */
441 	dlp = dip->di_dvp->dv_dlp;
442 	dls_link_add(dlp, dls_sap, dip);
443 
444 	return (0);
445 }
446 
447 void
448 dls_unbind(dls_channel_t dc)
449 {
450 	dls_impl_t	*dip = (dls_impl_t *)dc;
451 	dls_link_t	*dlp;
452 
453 	/*
454 	 * Unbind the dls_impl_t by removing it from the hash table in the
455 	 * dls_link_t.
456 	 *
457 	 * NOTE: This must be done without the dls_impl_t lock being held
458 	 *	 otherise deadlock may enuse.
459 	 */
460 	dlp = dip->di_dvp->dv_dlp;
461 	dls_link_remove(dlp, dip);
462 
463 	/*
464 	 * Mark the dls_impl_t as unable to receive packets This will make
465 	 * sure that 'receives in flight' will not come our way.
466 	 */
467 	dip->di_bound = B_FALSE;
468 }
469 
470 int
471 dls_promisc(dls_channel_t dc, uint32_t flags)
472 {
473 	dls_impl_t	*dip = (dls_impl_t *)dc;
474 	dls_link_t	*dlp;
475 	int		err = 0;
476 
477 	ASSERT(!(flags & ~(DLS_PROMISC_SAP | DLS_PROMISC_MULTI |
478 	    DLS_PROMISC_PHYS)));
479 
480 	/*
481 	 * Check if we need to turn on 'all sap' mode.
482 	 */
483 	rw_enter(&(dip->di_lock), RW_WRITER);
484 	dlp = dip->di_dvp->dv_dlp;
485 	if ((flags & DLS_PROMISC_SAP) &&
486 	    !(dip->di_promisc & DLS_PROMISC_SAP)) {
487 		dip->di_promisc |= DLS_PROMISC_SAP;
488 		if (!dip->di_bound)
489 			goto multi;
490 
491 		rw_exit(&(dip->di_lock));
492 		dls_link_remove(dlp, dip);
493 		dls_link_add(dlp, DLS_SAP_PROMISC, dip);
494 		rw_enter(&(dip->di_lock), RW_WRITER);
495 		goto multi;
496 	}
497 
498 	/*
499 	 * Check if we need to turn off 'all sap' mode.
500 	 */
501 	if (!(flags & DLS_PROMISC_SAP) &&
502 	    (dip->di_promisc & DLS_PROMISC_SAP)) {
503 		uint32_t dls_sap;
504 
505 		dip->di_promisc &= ~DLS_PROMISC_SAP;
506 		if (!dip->di_bound)
507 			goto multi;
508 
509 		rw_exit(&(dip->di_lock));
510 		dls_link_remove(dlp, dip);
511 		(void) mac_sap_verify(dip->di_mh, dip->di_sap, &dls_sap);
512 		dls_link_add(dlp, dls_sap, dip);
513 		rw_enter(&(dip->di_lock), RW_WRITER);
514 	}
515 
516 multi:
517 	/*
518 	 * It's easiest to add the txloop callback up-front; if promiscuous
519 	 * mode cannot be enabled, then we'll remove it before returning.
520 	 * Use dl_promisc_lock to prevent racing with another thread also
521 	 * manipulating the promiscuous state on another dls_impl_t associated
522 	 * with the same dls_link_t.
523 	 */
524 	mutex_enter(&dlp->dl_promisc_lock);
525 	if ((dlp->dl_npromisc == 0) && (flags & DLS_PROMISC_PHYS)) {
526 		ASSERT(dlp->dl_mth == NULL);
527 		dlp->dl_mth = mac_txloop_add(dlp->dl_mh, dls_link_txloop, dlp);
528 	}
529 
530 	/*
531 	 * Turn on or off 'all multicast' mode, if necessary.
532 	 */
533 	if (flags & DLS_PROMISC_MULTI) {
534 		if (!(dip->di_promisc & DLS_PROMISC_MULTI)) {
535 			if ((err = mac_promisc_set(dip->di_mh, B_TRUE,
536 			    MAC_DEVPROMISC)) != 0) {
537 				goto done;
538 			}
539 			dip->di_promisc |= DLS_PROMISC_MULTI;
540 		}
541 	} else {
542 		if (dip->di_promisc & DLS_PROMISC_MULTI) {
543 			if ((err = mac_promisc_set(dip->di_mh, B_FALSE,
544 			    MAC_DEVPROMISC)) != 0) {
545 				goto done;
546 			}
547 			dip->di_promisc &= ~DLS_PROMISC_MULTI;
548 		}
549 	}
550 
551 	/*
552 	 * Turn on or off 'all physical' mode, if necessary.
553 	 */
554 	if (flags & DLS_PROMISC_PHYS) {
555 		if (!(dip->di_promisc & DLS_PROMISC_PHYS)) {
556 			err = mac_promisc_set(dip->di_mh, B_TRUE, MAC_PROMISC);
557 			if (err != 0)
558 				goto done;
559 
560 			dip->di_promisc |= DLS_PROMISC_PHYS;
561 			dlp->dl_npromisc++;
562 		}
563 	} else {
564 		if (dip->di_promisc & DLS_PROMISC_PHYS) {
565 			err = mac_promisc_set(dip->di_mh, B_FALSE, MAC_PROMISC);
566 			if (err != 0)
567 				goto done;
568 
569 			dip->di_promisc &= ~DLS_PROMISC_PHYS;
570 			dlp->dl_npromisc--;
571 		}
572 	}
573 
574 done:
575 	if (dlp->dl_npromisc == 0 && dlp->dl_mth != NULL) {
576 		mac_txloop_remove(dlp->dl_mh, dlp->dl_mth);
577 		dlp->dl_mth = NULL;
578 	}
579 
580 	ASSERT(dlp->dl_npromisc == 0 || dlp->dl_mth != NULL);
581 	mutex_exit(&dlp->dl_promisc_lock);
582 
583 	rw_exit(&(dip->di_lock));
584 	return (err);
585 }
586 
587 int
588 dls_multicst_add(dls_channel_t dc, const uint8_t *addr)
589 {
590 	dls_impl_t		*dip = (dls_impl_t *)dc;
591 	int			err;
592 	dls_multicst_addr_t	**pp;
593 	dls_multicst_addr_t	*p;
594 	uint_t			addr_length;
595 
596 	/*
597 	 * Check whether the address is in the list of enabled addresses for
598 	 * this dls_impl_t.
599 	 */
600 	rw_enter(&(dip->di_lock), RW_WRITER);
601 	addr_length = dip->di_mip->mi_addr_length;
602 	for (pp = &(dip->di_dmap); (p = *pp) != NULL; pp = &(p->dma_nextp)) {
603 		if (bcmp(addr, p->dma_addr, addr_length) == 0) {
604 			/*
605 			 * It is there so there's nothing to do.
606 			 */
607 			err = 0;
608 			goto done;
609 		}
610 	}
611 
612 	/*
613 	 * Allocate a new list item.
614 	 */
615 	if ((p = kmem_zalloc(sizeof (dls_multicst_addr_t),
616 	    KM_NOSLEEP)) == NULL) {
617 		err = ENOMEM;
618 		goto done;
619 	}
620 
621 	/*
622 	 * Enable the address at the MAC.
623 	 */
624 	if ((err = mac_multicst_add(dip->di_mh, addr)) != 0) {
625 		kmem_free(p, sizeof (dls_multicst_addr_t));
626 		goto done;
627 	}
628 
629 	/*
630 	 * The address is now enabled at the MAC so add it to the list.
631 	 */
632 	bcopy(addr, p->dma_addr, addr_length);
633 	*pp = p;
634 
635 done:
636 	rw_exit(&(dip->di_lock));
637 	return (err);
638 }
639 
640 int
641 dls_multicst_remove(dls_channel_t dc, const uint8_t *addr)
642 {
643 	dls_impl_t		*dip = (dls_impl_t *)dc;
644 	int			err;
645 	dls_multicst_addr_t	**pp;
646 	dls_multicst_addr_t	*p;
647 	uint_t			addr_length;
648 
649 	/*
650 	 * Find the address in the list of enabled addresses for this
651 	 * dls_impl_t.
652 	 */
653 	rw_enter(&(dip->di_lock), RW_WRITER);
654 	addr_length = dip->di_mip->mi_addr_length;
655 	for (pp = &(dip->di_dmap); (p = *pp) != NULL; pp = &(p->dma_nextp)) {
656 		if (bcmp(addr, p->dma_addr, addr_length) == 0)
657 			break;
658 	}
659 
660 	/*
661 	 * If we walked to the end of the list then the given address is
662 	 * not currently enabled for this dls_impl_t.
663 	 */
664 	if (p == NULL) {
665 		err = ENOENT;
666 		goto done;
667 	}
668 
669 	/*
670 	 * Disable the address at the MAC.
671 	 */
672 	if ((err = mac_multicst_remove(dip->di_mh, addr)) != 0)
673 		goto done;
674 
675 	/*
676 	 * Remove the address from the list.
677 	 */
678 	*pp = p->dma_nextp;
679 	kmem_free(p, sizeof (dls_multicst_addr_t));
680 
681 done:
682 	rw_exit(&(dip->di_lock));
683 	return (err);
684 }
685 
686 mblk_t *
687 dls_header(dls_channel_t dc, const uint8_t *addr, uint16_t sap, uint_t pri,
688     mblk_t **payloadp)
689 {
690 	dls_impl_t *dip = (dls_impl_t *)dc;
691 	uint16_t vid;
692 	size_t extra_len;
693 	uint16_t mac_sap;
694 	mblk_t *mp, *payload;
695 	boolean_t is_ethernet = (dip->di_mip->mi_media == DL_ETHER);
696 	struct ether_vlan_header *evhp;
697 
698 	vid = dip->di_dvp->dv_id;
699 	payload = (payloadp == NULL) ? NULL : (*payloadp);
700 
701 	/*
702 	 * If the following conditions are satisfied:
703 	 *	- This is not a ETHERTYPE_VLAN listener; and
704 	 *	- This is either a VLAN stream or this is a physical stream
705 	 *	  but the priority is not 0.
706 	 *
707 	 * then we know ahead of time that we'll need to fill in additional
708 	 * VLAN information in the link-layer header. We will tell the MAC
709 	 * layer to pre-allocate some space at the end of the Ethernet
710 	 * header for us.
711 	 */
712 	if (is_ethernet && sap != ETHERTYPE_VLAN &&
713 	    (vid != VLAN_ID_NONE || pri != 0)) {
714 		extra_len = sizeof (struct ether_vlan_header) -
715 		    sizeof (struct ether_header);
716 		mac_sap = ETHERTYPE_VLAN;
717 	} else {
718 		extra_len = 0;
719 		mac_sap = sap;
720 	}
721 
722 	mp = mac_header(dip->di_mh, addr, mac_sap, payload, extra_len);
723 	if (mp == NULL)
724 		return (NULL);
725 
726 	if ((vid == VLAN_ID_NONE && pri == 0) || !is_ethernet)
727 		return (mp);
728 
729 	/*
730 	 * Fill in the tag information.
731 	 */
732 	ASSERT(MBLKL(mp) == sizeof (struct ether_header));
733 	if (extra_len != 0) {
734 		mp->b_wptr += extra_len;
735 		evhp = (struct ether_vlan_header *)mp->b_rptr;
736 		evhp->ether_tci = htons(VLAN_TCI(pri, ETHER_CFI, vid));
737 		evhp->ether_type = htons(sap);
738 	} else {
739 		/*
740 		 * The stream is ETHERTYPE_VLAN listener, so its VLAN tag is
741 		 * in the payload. Update the priority.
742 		 */
743 		struct ether_vlan_extinfo *extinfo;
744 		size_t len = sizeof (struct ether_vlan_extinfo);
745 
746 		ASSERT(sap == ETHERTYPE_VLAN);
747 		ASSERT(payload != NULL);
748 
749 		if ((DB_REF(payload) > 1) || (MBLKL(payload) < len)) {
750 			mblk_t *newmp;
751 
752 			/*
753 			 * Because some DLS consumers only check the db_ref
754 			 * count of the first mblk, we pullup 'payload' into
755 			 * a single mblk.
756 			 */
757 			newmp = msgpullup(payload, -1);
758 			if ((newmp == NULL) || (MBLKL(newmp) < len)) {
759 				freemsg(newmp);
760 				freemsg(mp);
761 				return (NULL);
762 			} else {
763 				freemsg(payload);
764 				*payloadp = payload = newmp;
765 			}
766 		}
767 
768 		extinfo = (struct ether_vlan_extinfo *)payload->b_rptr;
769 		extinfo->ether_tci = htons(VLAN_TCI(pri, ETHER_CFI,
770 		    VLAN_ID(ntohs(extinfo->ether_tci))));
771 	}
772 	return (mp);
773 }
774 
775 int
776 dls_header_info(dls_channel_t dc, mblk_t *mp, mac_header_info_t *mhip)
777 {
778 	return (dls_link_header_info(((dls_impl_t *)dc)->di_dvp->dv_dlp,
779 	    mp, mhip));
780 }
781 
782 void
783 dls_rx_set(dls_channel_t dc, dls_rx_t rx, void *arg)
784 {
785 	dls_impl_t	*dip = (dls_impl_t *)dc;
786 
787 	rw_enter(&(dip->di_lock), RW_WRITER);
788 	dip->di_rx = rx;
789 	dip->di_rx_arg = arg;
790 	rw_exit(&(dip->di_lock));
791 }
792 
793 mblk_t *
794 dls_tx(dls_channel_t dc, mblk_t *mp)
795 {
796 	const mac_txinfo_t *mtp = ((dls_impl_t *)dc)->di_txinfo;
797 
798 	return (mtp->mt_fn(mtp->mt_arg, mp));
799 }
800 
801 boolean_t
802 dls_accept(dls_impl_t *dip, mac_header_info_t *mhip, dls_rx_t *di_rx,
803     void **di_rx_arg)
804 {
805 	dls_multicst_addr_t	*dmap;
806 	size_t			addr_length = dip->di_mip->mi_addr_length;
807 
808 	/*
809 	 * We must not accept packets if the dls_impl_t is not marked as bound
810 	 * or is being removed.
811 	 */
812 	rw_enter(&(dip->di_lock), RW_READER);
813 	if (!dip->di_bound || dip->di_removing)
814 		goto refuse;
815 
816 	/*
817 	 * If the dls_impl_t is in 'all physical' mode then always accept.
818 	 */
819 	if (dip->di_promisc & DLS_PROMISC_PHYS)
820 		goto accept;
821 
822 	/*
823 	 * For non-promiscs-phys streams, filter out the packets looped back
824 	 * from the underlying driver because of promiscuous setting.
825 	 */
826 	if (mhip->mhi_prom_looped)
827 		goto refuse;
828 
829 	switch (mhip->mhi_dsttype) {
830 	case MAC_ADDRTYPE_UNICAST:
831 		/*
832 		 * Check to see if the destination address matches the
833 		 * dls_impl_t unicast address.
834 		 */
835 		if (memcmp(mhip->mhi_daddr, dip->di_unicst_addr, addr_length) ==
836 		    0) {
837 			goto accept;
838 		}
839 		break;
840 	case MAC_ADDRTYPE_MULTICAST:
841 		/*
842 		 * Check the address against the list of addresses enabled
843 		 * for this dls_impl_t or accept it unconditionally if the
844 		 * dls_impl_t is in 'all multicast' mode.
845 		 */
846 		if (dip->di_promisc & DLS_PROMISC_MULTI)
847 			goto accept;
848 		for (dmap = dip->di_dmap; dmap != NULL;
849 		    dmap = dmap->dma_nextp) {
850 			if (memcmp(mhip->mhi_daddr, dmap->dma_addr,
851 			    addr_length) == 0) {
852 				goto accept;
853 			}
854 		}
855 		break;
856 	case MAC_ADDRTYPE_BROADCAST:
857 		/*
858 		 * If the address is broadcast then the dls_impl_t will
859 		 * always accept it.
860 		 */
861 		goto accept;
862 	}
863 
864 refuse:
865 	rw_exit(&(dip->di_lock));
866 	return (B_FALSE);
867 
868 accept:
869 	/*
870 	 * Since we hold di_lock here, the returned di_rx and di_rx_arg will
871 	 * always be in sync.
872 	 */
873 	*di_rx = dip->di_rx;
874 	*di_rx_arg = dip->di_rx_arg;
875 	rw_exit(&(dip->di_lock));
876 	return (B_TRUE);
877 }
878 
879 /* ARGSUSED */
880 boolean_t
881 dls_accept_loopback(dls_impl_t *dip, mac_header_info_t *mhip, dls_rx_t *di_rx,
882     void **di_rx_arg)
883 {
884 	/*
885 	 * We must not accept packets if the dls_impl_t is not marked as bound
886 	 * or is being removed.
887 	 */
888 	rw_enter(&(dip->di_lock), RW_READER);
889 	if (!dip->di_bound || dip->di_removing)
890 		goto refuse;
891 
892 	/*
893 	 * A dls_impl_t should only accept loopback packets if it is in
894 	 * 'all physical' mode.
895 	 */
896 	if (dip->di_promisc & DLS_PROMISC_PHYS)
897 		goto accept;
898 
899 refuse:
900 	rw_exit(&(dip->di_lock));
901 	return (B_FALSE);
902 
903 accept:
904 	/*
905 	 * Since we hold di_lock here, the returned di_rx and di_rx_arg will
906 	 * always be in sync.
907 	 */
908 	*di_rx = dip->di_rx;
909 	*di_rx_arg = dip->di_rx_arg;
910 	rw_exit(&(dip->di_lock));
911 	return (B_TRUE);
912 }
913 
914 boolean_t
915 dls_mac_active_set(dls_link_t *dlp)
916 {
917 	mutex_enter(&dlp->dl_lock);
918 
919 	/*
920 	 * If this is the first active client on this link, notify
921 	 * the mac that we're becoming an active client.
922 	 */
923 	if (dlp->dl_nactive == 0 && !mac_active_shareable_set(dlp->dl_mh)) {
924 		mutex_exit(&dlp->dl_lock);
925 		return (B_FALSE);
926 	}
927 	dlp->dl_nactive++;
928 	mutex_exit(&dlp->dl_lock);
929 	return (B_TRUE);
930 }
931 
932 void
933 dls_mac_active_clear(dls_link_t *dlp)
934 {
935 	mutex_enter(&dlp->dl_lock);
936 	if (--dlp->dl_nactive == 0)
937 		mac_active_clear(dlp->dl_mh);
938 	mutex_exit(&dlp->dl_lock);
939 }
940 
941 boolean_t
942 dls_active_set(dls_channel_t dc)
943 {
944 	dls_impl_t	*dip = (dls_impl_t *)dc;
945 	dls_link_t	*dlp = dip->di_dvp->dv_dlp;
946 
947 	rw_enter(&dip->di_lock, RW_WRITER);
948 
949 	/* If we're already active, then there's nothing more to do. */
950 	if (dip->di_active) {
951 		rw_exit(&dip->di_lock);
952 		return (B_TRUE);
953 	}
954 
955 	if (!dls_mac_active_set(dlp)) {
956 		rw_exit(&dip->di_lock);
957 		return (B_FALSE);
958 	}
959 	dip->di_active = B_TRUE;
960 	rw_exit(&dip->di_lock);
961 	return (B_TRUE);
962 }
963 
964 void
965 dls_active_clear(dls_channel_t dc)
966 {
967 	dls_impl_t	*dip = (dls_impl_t *)dc;
968 	dls_link_t	*dlp = dip->di_dvp->dv_dlp;
969 
970 	rw_enter(&dip->di_lock, RW_WRITER);
971 
972 	if (!dip->di_active)
973 		goto out;
974 	dip->di_active = B_FALSE;
975 
976 	dls_mac_active_clear(dlp);
977 
978 out:
979 	rw_exit(&dip->di_lock);
980 }
981