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