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