xref: /titanic_41/usr/src/uts/common/io/mac/mac.c (revision 890e8ff10cfc85bc7d33064a9a30c3e8477b4813)
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  * MAC Services Module
30  */
31 
32 #include <sys/types.h>
33 #include <sys/conf.h>
34 #include <sys/stat.h>
35 #include <sys/stream.h>
36 #include <sys/strsun.h>
37 #include <sys/strsubr.h>
38 #include <sys/dlpi.h>
39 #include <sys/modhash.h>
40 #include <sys/mac.h>
41 #include <sys/mac_impl.h>
42 #include <sys/dls.h>
43 #include <sys/dld.h>
44 
45 #define	IMPL_HASHSZ	67	/* prime */
46 
47 static kmem_cache_t	*i_mac_impl_cachep;
48 static mod_hash_t	*i_mac_impl_hash;
49 krwlock_t		i_mac_impl_lock;
50 uint_t			i_mac_impl_count;
51 
52 static void i_mac_notify_task(void *);
53 
54 /*
55  * Private functions.
56  */
57 
58 /*ARGSUSED*/
59 static boolean_t
60 i_mac_ether_unicst_verify(mac_impl_t *mip, const uint8_t *addr)
61 {
62 	/*
63 	 * Check the address is not a group address.
64 	 */
65 	if (addr[0] & 0x01)
66 		return (B_FALSE);
67 
68 	return (B_TRUE);
69 }
70 
71 static boolean_t
72 i_mac_ether_multicst_verify(mac_impl_t *mip, const uint8_t *addr)
73 {
74 	mac_t		*mp = mip->mi_mp;
75 
76 	/*
77 	 * Check the address is a group address.
78 	 */
79 	if (!(addr[0] & 0x01))
80 		return (B_FALSE);
81 
82 	/*
83 	 * Check the address is not the media broadcast address.
84 	 */
85 	if (bcmp(addr, mp->m_info.mi_brdcst_addr, mip->mi_addr_length) == 0)
86 		return (B_FALSE);
87 
88 	return (B_TRUE);
89 }
90 
91 /*ARGSUSED*/
92 static int
93 i_mac_constructor(void *buf, void *arg, int kmflag)
94 {
95 	mac_impl_t	*mip = buf;
96 
97 	bzero(buf, sizeof (mac_impl_t));
98 
99 	mip->mi_link = LINK_STATE_UNKNOWN;
100 
101 	rw_init(&mip->mi_state_lock, NULL, RW_DRIVER, NULL);
102 	rw_init(&mip->mi_data_lock, NULL, RW_DRIVER, NULL);
103 	rw_init(&mip->mi_notify_lock, NULL, RW_DRIVER, NULL);
104 	rw_init(&mip->mi_rx_lock, NULL, RW_DRIVER, NULL);
105 	rw_init(&mip->mi_txloop_lock, NULL, RW_DRIVER, NULL);
106 	rw_init(&mip->mi_resource_lock, NULL, RW_DRIVER, NULL);
107 	mutex_init(&mip->mi_activelink_lock, NULL, MUTEX_DEFAULT, NULL);
108 	mutex_init(&mip->mi_notify_ref_lock, NULL, MUTEX_DRIVER, NULL);
109 	cv_init(&mip->mi_notify_cv, NULL, CV_DRIVER, NULL);
110 	return (0);
111 }
112 
113 /*ARGSUSED*/
114 static void
115 i_mac_destructor(void *buf, void *arg)
116 {
117 	mac_impl_t	*mip = buf;
118 
119 	ASSERT(mip->mi_mp == NULL);
120 	ASSERT(mip->mi_ref == 0);
121 	ASSERT(mip->mi_active == 0);
122 	ASSERT(mip->mi_link == LINK_STATE_UNKNOWN);
123 	ASSERT(mip->mi_devpromisc == 0);
124 	ASSERT(mip->mi_promisc == 0);
125 	ASSERT(mip->mi_mmap == NULL);
126 	ASSERT(mip->mi_mnfp == NULL);
127 	ASSERT(mip->mi_resource_add == NULL);
128 	ASSERT(mip->mi_ksp == NULL);
129 
130 	rw_destroy(&mip->mi_state_lock);
131 	rw_destroy(&mip->mi_data_lock);
132 	rw_destroy(&mip->mi_notify_lock);
133 	rw_destroy(&mip->mi_rx_lock);
134 	rw_destroy(&mip->mi_txloop_lock);
135 	rw_destroy(&mip->mi_resource_lock);
136 	mutex_destroy(&mip->mi_activelink_lock);
137 	mutex_destroy(&mip->mi_notify_ref_lock);
138 	cv_destroy(&mip->mi_notify_cv);
139 }
140 
141 static int
142 i_mac_create(mac_t *mp)
143 {
144 	dev_info_t	*dip;
145 	mac_impl_t	*mip;
146 	int		err = 0;
147 
148 	dip = mp->m_dip;
149 	ASSERT(dip != NULL);
150 	ASSERT(ddi_get_instance(dip) >= 0);
151 
152 	/*
153 	 * Allocate a new mac_impl_t.
154 	 */
155 	mip = kmem_cache_alloc(i_mac_impl_cachep, KM_SLEEP);
156 
157 	/*
158 	 * Construct a name.
159 	 */
160 	(void) snprintf(mip->mi_dev, MAXNAMELEN - 1, "%s%d",
161 	    ddi_driver_name(dip), ddi_get_instance(dip));
162 	mip->mi_port = mp->m_port;
163 
164 	MAC_NAME(mip->mi_name, mip->mi_dev, mip->mi_port);
165 
166 	/*
167 	 * Set the mac_t/mac_impl_t cross-references.
168 	 */
169 	mip->mi_mp = mp;
170 	mp->m_impl = (void *)mip;
171 
172 	/*
173 	 * The mac is not ready for open yet.
174 	 */
175 	mip->mi_disabled = B_TRUE;
176 
177 	/*
178 	 * Insert the hash table entry.
179 	 */
180 	rw_enter(&i_mac_impl_lock, RW_WRITER);
181 	if (mod_hash_insert(i_mac_impl_hash,
182 	    (mod_hash_key_t)mip->mi_name, (mod_hash_val_t)mip) != 0) {
183 		kmem_cache_free(i_mac_impl_cachep, mip);
184 		err = EEXIST;
185 		goto done;
186 	}
187 	i_mac_impl_count++;
188 
189 	/*
190 	 * Copy the fixed 'factory' MAC address from the immutable info.
191 	 * This is taken to be the MAC address currently in use.
192 	 */
193 	mip->mi_addr_length = mp->m_info.mi_addr_length;
194 	bcopy(mp->m_info.mi_unicst_addr, mip->mi_addr, mip->mi_addr_length);
195 
196 	/*
197 	 * Set up the address verification functions.
198 	 */
199 	ASSERT(mp->m_info.mi_media == DL_ETHER);
200 	mip->mi_unicst_verify = i_mac_ether_unicst_verify;
201 	mip->mi_multicst_verify = i_mac_ether_multicst_verify;
202 
203 	/*
204 	 * Set up the two possible transmit routines.
205 	 */
206 	mip->mi_txinfo.mt_fn = mp->m_tx;
207 	mip->mi_txinfo.mt_arg = mp->m_driver;
208 	mip->mi_txloopinfo.mt_fn = mac_txloop;
209 	mip->mi_txloopinfo.mt_arg = mip;
210 
211 	/*
212 	 * Initialize the kstats for this device.
213 	 */
214 	mac_stat_create(mip);
215 
216 done:
217 	rw_exit(&i_mac_impl_lock);
218 	return (err);
219 }
220 
221 static void
222 i_mac_destroy(mac_t *mp)
223 {
224 	mac_impl_t		*mip = mp->m_impl;
225 	mac_multicst_addr_t	*p, *nextp;
226 	mod_hash_val_t		val;
227 
228 	rw_enter(&i_mac_impl_lock, RW_WRITER);
229 
230 	ASSERT(mip->mi_ref == 0);
231 	ASSERT(!mip->mi_activelink);
232 
233 	/*
234 	 * Destroy the kstats.
235 	 */
236 	mac_stat_destroy(mip);
237 
238 	/*
239 	 * Remove and destroy the hash table entry.
240 	 */
241 	(void) mod_hash_remove(i_mac_impl_hash,
242 	    (mod_hash_key_t)mip->mi_name, &val);
243 	ASSERT(mip == (mac_impl_t *)val);
244 
245 	ASSERT(i_mac_impl_count > 0);
246 	i_mac_impl_count--;
247 
248 	/*
249 	 * Free the list of multicast addresses.
250 	 */
251 	for (p = mip->mi_mmap; p != NULL; p = nextp) {
252 		nextp = p->mma_nextp;
253 		kmem_free(p, sizeof (mac_multicst_addr_t));
254 	}
255 	mip->mi_mmap = NULL;
256 
257 	/*
258 	 * Clean up the mac_impl_t ready to go back into the cache.
259 	 */
260 	mp->m_impl = NULL;
261 	mip->mi_mp = NULL;
262 	mip->mi_link = LINK_STATE_UNKNOWN;
263 	mip->mi_disabled = B_FALSE;
264 
265 	/*
266 	 * Free the structure back to the cache.
267 	 */
268 	kmem_cache_free(i_mac_impl_cachep, mip);
269 
270 	rw_exit(&i_mac_impl_lock);
271 }
272 
273 static void
274 i_mac_notify(mac_impl_t *mip, mac_notify_type_t type)
275 {
276 	mac_notify_task_arg_t	*mnta;
277 
278 	rw_enter(&i_mac_impl_lock, RW_READER);
279 	if (mip->mi_disabled)
280 		goto exit;
281 
282 	if ((mnta = kmem_alloc(sizeof (*mnta), KM_NOSLEEP)) == NULL) {
283 		cmn_err(CE_WARN, "i_mac_notify(%s, 0x%x): memory "
284 		    "allocation failed", mip->mi_name, type);
285 		goto exit;
286 	}
287 
288 	mnta->mnt_mip = mip;
289 	mnta->mnt_type = type;
290 
291 	mutex_enter(&mip->mi_notify_ref_lock);
292 	mip->mi_notify_ref++;
293 	mutex_exit(&mip->mi_notify_ref_lock);
294 
295 	rw_exit(&i_mac_impl_lock);
296 
297 	if (taskq_dispatch(system_taskq, i_mac_notify_task, mnta,
298 	    TQ_NOSLEEP) == NULL) {
299 		cmn_err(CE_WARN, "i_mac_notify(%s, 0x%x): taskq dispatch "
300 		    "failed", mip->mi_name, type);
301 
302 		mutex_enter(&mip->mi_notify_ref_lock);
303 		if (--mip->mi_notify_ref == 0)
304 			cv_signal(&mip->mi_notify_cv);
305 		mutex_exit(&mip->mi_notify_ref_lock);
306 
307 		kmem_free(mnta, sizeof (*mnta));
308 	}
309 	return;
310 
311 exit:
312 	rw_exit(&i_mac_impl_lock);
313 }
314 
315 static void
316 i_mac_notify_task(void *notify_arg)
317 {
318 	mac_notify_task_arg_t	*mnta = (mac_notify_task_arg_t *)notify_arg;
319 	mac_impl_t		*mip;
320 	mac_notify_type_t	type;
321 	mac_notify_fn_t		*mnfp;
322 	mac_notify_t		notify;
323 	void			*arg;
324 
325 	mip = mnta->mnt_mip;
326 	type = mnta->mnt_type;
327 	kmem_free(mnta, sizeof (*mnta));
328 
329 	/*
330 	 * Walk the list of notifications.
331 	 */
332 	rw_enter(&mip->mi_notify_lock, RW_READER);
333 	for (mnfp = mip->mi_mnfp; mnfp != NULL; mnfp = mnfp->mnf_nextp) {
334 		notify = mnfp->mnf_fn;
335 		arg = mnfp->mnf_arg;
336 
337 		ASSERT(notify != NULL);
338 		notify(arg, type);
339 	}
340 	rw_exit(&mip->mi_notify_lock);
341 
342 	mutex_enter(&mip->mi_notify_ref_lock);
343 	if (--mip->mi_notify_ref == 0)
344 		cv_signal(&mip->mi_notify_cv);
345 	mutex_exit(&mip->mi_notify_ref_lock);
346 }
347 
348 /*
349  * Module initialization functions.
350  */
351 
352 void
353 mac_init(void)
354 {
355 	i_mac_impl_cachep = kmem_cache_create("mac_impl_cache",
356 	    sizeof (mac_impl_t), 0, i_mac_constructor, i_mac_destructor, NULL,
357 	    NULL, NULL, 0);
358 	ASSERT(i_mac_impl_cachep != NULL);
359 
360 	i_mac_impl_hash = mod_hash_create_extended("mac_impl_hash",
361 	    IMPL_HASHSZ, mod_hash_null_keydtor, mod_hash_null_valdtor,
362 	    mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP);
363 	rw_init(&i_mac_impl_lock, NULL, RW_DEFAULT, NULL);
364 	i_mac_impl_count = 0;
365 }
366 
367 int
368 mac_fini(void)
369 {
370 	if (i_mac_impl_count > 0)
371 		return (EBUSY);
372 
373 	mod_hash_destroy_hash(i_mac_impl_hash);
374 	rw_destroy(&i_mac_impl_lock);
375 
376 	kmem_cache_destroy(i_mac_impl_cachep);
377 	return (0);
378 }
379 
380 /*
381  * Client functions.
382  */
383 
384 int
385 mac_open(const char *dev, uint_t port, mac_handle_t *mhp)
386 {
387 	char		name[MAXNAMELEN];
388 	char		driver[MAXNAMELEN];
389 	uint_t		instance;
390 	major_t		major;
391 	dev_info_t	*dip;
392 	mac_impl_t	*mip;
393 	int		err;
394 
395 	/*
396 	 * Check the device name length to make sure it won't overflow our
397 	 * buffer.
398 	 */
399 	if (strlen(dev) >= MAXNAMELEN)
400 		return (EINVAL);
401 
402 	/*
403 	 * Split the device name into driver and instance components.
404 	 */
405 	if (ddi_parse(dev, driver, &instance) != DDI_SUCCESS)
406 		return (EINVAL);
407 
408 	/*
409 	 * Get the major number of the driver.
410 	 */
411 	if ((major = ddi_name_to_major(driver)) == (major_t)-1)
412 		return (EINVAL);
413 
414 	/*
415 	 * Hold the given instance to prevent it from being detached.
416 	 * This will also attach the instance if it is not currently attached.
417 	 * Currently we ensure that mac_register() (called by the driver's
418 	 * attach entry point) and all code paths under it cannot possibly
419 	 * call mac_open() because this would lead to a recursive attach
420 	 * panic.
421 	 */
422 	if ((dip = ddi_hold_devi_by_instance(major, instance, 0)) == NULL)
423 		return (EINVAL);
424 
425 	/*
426 	 * Construct the name of the MAC interface.
427 	 */
428 	MAC_NAME(name, dev, port);
429 
430 	/*
431 	 * Look up its entry in the global hash table.
432 	 */
433 again:
434 	rw_enter(&i_mac_impl_lock, RW_WRITER);
435 	err = mod_hash_find(i_mac_impl_hash, (mod_hash_key_t)name,
436 	    (mod_hash_val_t *)&mip);
437 	if (err != 0) {
438 		err = ENOENT;
439 		goto failed;
440 	}
441 
442 	if (mip->mi_disabled) {
443 		rw_exit(&i_mac_impl_lock);
444 		goto again;
445 	}
446 
447 	/*
448 	 * We currently only support the DL_ETHER media type.
449 	 */
450 	ASSERT(mip->mi_mp->m_info.mi_media == DL_ETHER);
451 	mip->mi_ref++;
452 	rw_exit(&i_mac_impl_lock);
453 
454 	*mhp = (mac_handle_t)mip;
455 	return (0);
456 
457 failed:
458 	rw_exit(&i_mac_impl_lock);
459 	ddi_release_devi(dip);
460 	return (err);
461 }
462 
463 void
464 mac_close(mac_handle_t mh)
465 {
466 	mac_impl_t	*mip = (mac_impl_t *)mh;
467 	dev_info_t	*dip = mip->mi_mp->m_dip;
468 
469 	rw_enter(&i_mac_impl_lock, RW_WRITER);
470 
471 	ASSERT(mip->mi_ref != 0);
472 	if (--mip->mi_ref == 0) {
473 		ASSERT(!mip->mi_activelink);
474 	}
475 	ddi_release_devi(dip);
476 	rw_exit(&i_mac_impl_lock);
477 }
478 
479 const mac_info_t *
480 mac_info(mac_handle_t mh)
481 {
482 	mac_impl_t	*mip = (mac_impl_t *)mh;
483 	mac_t		*mp = mip->mi_mp;
484 
485 	/*
486 	 * Return a pointer to the mac_info_t embedded in the mac_t.
487 	 */
488 	return (&(mp->m_info));
489 }
490 
491 dev_info_t *
492 mac_devinfo_get(mac_handle_t mh)
493 {
494 	return (((mac_impl_t *)mh)->mi_mp->m_dip);
495 }
496 
497 uint64_t
498 mac_stat_get(mac_handle_t mh, enum mac_stat stat)
499 {
500 	mac_impl_t	*mip = (mac_impl_t *)mh;
501 	mac_t		*mp = mip->mi_mp;
502 
503 	ASSERT(mp->m_info.mi_stat[stat]);
504 	ASSERT(mp->m_stat != NULL);
505 
506 	/*
507 	 * Call the driver to get the given statistic.
508 	 */
509 	return (mp->m_stat(mp->m_driver, stat));
510 }
511 
512 int
513 mac_start(mac_handle_t mh)
514 {
515 	mac_impl_t	*mip = (mac_impl_t *)mh;
516 	mac_t		*mp = mip->mi_mp;
517 	int		err;
518 
519 	ASSERT(mp->m_start != NULL);
520 
521 	rw_enter(&(mip->mi_state_lock), RW_WRITER);
522 
523 	/*
524 	 * Check whether the device is already started.
525 	 */
526 	if (mip->mi_active++ != 0) {
527 		/*
528 		 * It's already started so there's nothing more to do.
529 		 */
530 		err = 0;
531 		goto done;
532 	}
533 
534 	/*
535 	 * Start the device.
536 	 */
537 	if ((err = mp->m_start(mp->m_driver)) != 0)
538 		--mip->mi_active;
539 
540 done:
541 	rw_exit(&(mip->mi_state_lock));
542 	return (err);
543 }
544 
545 void
546 mac_stop(mac_handle_t mh)
547 {
548 	mac_impl_t	*mip = (mac_impl_t *)mh;
549 	mac_t		*mp = mip->mi_mp;
550 
551 	ASSERT(mp->m_stop != NULL);
552 
553 	rw_enter(&(mip->mi_state_lock), RW_WRITER);
554 
555 	/*
556 	 * Check whether the device is still needed.
557 	 */
558 	ASSERT(mip->mi_active != 0);
559 	if (--mip->mi_active != 0) {
560 		/*
561 		 * It's still needed so there's nothing more to do.
562 		 */
563 		goto done;
564 	}
565 
566 	/*
567 	 * Stop the device.
568 	 */
569 	mp->m_stop(mp->m_driver);
570 
571 done:
572 	rw_exit(&(mip->mi_state_lock));
573 }
574 
575 int
576 mac_multicst_add(mac_handle_t mh, const uint8_t *addr)
577 {
578 	mac_impl_t		*mip = (mac_impl_t *)mh;
579 	mac_t			*mp = mip->mi_mp;
580 	mac_multicst_addr_t	**pp;
581 	mac_multicst_addr_t	*p;
582 	int			err;
583 
584 	ASSERT(mp->m_multicst != NULL);
585 
586 	/*
587 	 * Verify the address.
588 	 */
589 	if (!(mip->mi_multicst_verify(mip, addr)))
590 		return (EINVAL);
591 
592 	/*
593 	 * Check whether the given address is already enabled.
594 	 */
595 	rw_enter(&(mip->mi_data_lock), RW_WRITER);
596 	for (pp = &(mip->mi_mmap); (p = *pp) != NULL; pp = &(p->mma_nextp)) {
597 		if (bcmp(p->mma_addr, addr, mip->mi_addr_length) == 0) {
598 			/*
599 			 * The address is already enabled so just bump the
600 			 * reference count.
601 			 */
602 			p->mma_ref++;
603 			err = 0;
604 			goto done;
605 		}
606 	}
607 
608 	/*
609 	 * Allocate a new list entry.
610 	 */
611 	if ((p = kmem_zalloc(sizeof (mac_multicst_addr_t),
612 	    KM_NOSLEEP)) == NULL) {
613 		err = ENOMEM;
614 		goto done;
615 	}
616 
617 	/*
618 	 * Enable a new multicast address.
619 	 */
620 	if ((err = mp->m_multicst(mp->m_driver, B_TRUE, addr)) != 0) {
621 		kmem_free(p, sizeof (mac_multicst_addr_t));
622 		goto done;
623 	}
624 
625 	/*
626 	 * Add the address to the list of enabled addresses.
627 	 */
628 	bcopy(addr, p->mma_addr, mip->mi_addr_length);
629 	p->mma_ref++;
630 	*pp = p;
631 
632 done:
633 	rw_exit(&(mip->mi_data_lock));
634 	return (err);
635 }
636 
637 int
638 mac_multicst_remove(mac_handle_t mh, const uint8_t *addr)
639 {
640 	mac_impl_t		*mip = (mac_impl_t *)mh;
641 	mac_t			*mp = mip->mi_mp;
642 	mac_multicst_addr_t	**pp;
643 	mac_multicst_addr_t	*p;
644 	int			err;
645 
646 	ASSERT(mp->m_multicst != NULL);
647 
648 	/*
649 	 * Find the entry in the list for the given address.
650 	 */
651 	rw_enter(&(mip->mi_data_lock), RW_WRITER);
652 	for (pp = &(mip->mi_mmap); (p = *pp) != NULL; pp = &(p->mma_nextp)) {
653 		if (bcmp(p->mma_addr, addr, mip->mi_addr_length) == 0) {
654 			if (--p->mma_ref == 0)
655 				break;
656 
657 			/*
658 			 * There is still a reference to this address so
659 			 * there's nothing more to do.
660 			 */
661 			err = 0;
662 			goto done;
663 		}
664 	}
665 
666 	/*
667 	 * We did not find an entry for the given address so it is not
668 	 * currently enabled.
669 	 */
670 	if (p == NULL) {
671 		err = ENOENT;
672 		goto done;
673 	}
674 	ASSERT(p->mma_ref == 0);
675 
676 	/*
677 	 * Disable the multicast address.
678 	 */
679 	if ((err = mp->m_multicst(mp->m_driver, B_FALSE, addr)) != 0) {
680 		p->mma_ref++;
681 		goto done;
682 	}
683 
684 	/*
685 	 * Remove it from the list.
686 	 */
687 	*pp = p->mma_nextp;
688 	kmem_free(p, sizeof (mac_multicst_addr_t));
689 
690 done:
691 	rw_exit(&(mip->mi_data_lock));
692 	return (err);
693 }
694 
695 int
696 mac_unicst_set(mac_handle_t mh, const uint8_t *addr)
697 {
698 	mac_impl_t	*mip = (mac_impl_t *)mh;
699 	mac_t		*mp = mip->mi_mp;
700 	int		err;
701 	boolean_t	notify = B_FALSE;
702 
703 	ASSERT(mp->m_unicst != NULL);
704 
705 	/*
706 	 * Verify the address.
707 	 */
708 	if (!(mip->mi_unicst_verify(mip, addr)))
709 		return (EINVAL);
710 
711 	/*
712 	 * Program the new unicast address.
713 	 */
714 	rw_enter(&(mip->mi_data_lock), RW_WRITER);
715 
716 	/*
717 	 * If address doesn't change, do nothing.
718 	 * This check is necessary otherwise it may call into mac_unicst_set
719 	 * recursively.
720 	 */
721 	if (bcmp(addr, mip->mi_addr, mip->mi_addr_length) == 0) {
722 		err = 0;
723 		goto done;
724 	}
725 
726 	if ((err = mp->m_unicst(mp->m_driver, addr)) != 0)
727 		goto done;
728 
729 	/*
730 	 * Save the address and flag that we need to send a notification.
731 	 */
732 	bcopy(addr, mip->mi_addr, mip->mi_addr_length);
733 	notify = B_TRUE;
734 
735 done:
736 	rw_exit(&(mip->mi_data_lock));
737 
738 	if (notify)
739 		i_mac_notify(mip, MAC_NOTE_UNICST);
740 
741 	return (err);
742 }
743 
744 void
745 mac_unicst_get(mac_handle_t mh, uint8_t *addr)
746 {
747 	mac_impl_t	*mip = (mac_impl_t *)mh;
748 
749 	/*
750 	 * Copy out the current unicast address.
751 	 */
752 	rw_enter(&(mip->mi_data_lock), RW_READER);
753 	bcopy(mip->mi_addr, addr, mip->mi_addr_length);
754 	rw_exit(&(mip->mi_data_lock));
755 }
756 
757 int
758 mac_promisc_set(mac_handle_t mh, boolean_t on, mac_promisc_type_t ptype)
759 {
760 	mac_impl_t	*mip = (mac_impl_t *)mh;
761 	mac_t		*mp = mip->mi_mp;
762 	int		err = 0;
763 
764 	ASSERT(mp->m_promisc != NULL);
765 	ASSERT(ptype == MAC_DEVPROMISC || ptype == MAC_PROMISC);
766 
767 	/*
768 	 * Determine whether we should enable or disable promiscuous mode.
769 	 * For details on the distinction between "device promiscuous mode"
770 	 * and "MAC promiscuous mode", see PSARC/2005/289.
771 	 */
772 	rw_enter(&(mip->mi_data_lock), RW_WRITER);
773 	if (on) {
774 		/*
775 		 * Enable promiscuous mode on the device if not yet enabled.
776 		 */
777 		if (mip->mi_devpromisc++ == 0) {
778 			if ((err = mp->m_promisc(mp->m_driver, B_TRUE)) != 0) {
779 				mip->mi_devpromisc--;
780 				goto done;
781 			}
782 			i_mac_notify(mip, MAC_NOTE_DEVPROMISC);
783 		}
784 
785 		/*
786 		 * Enable promiscuous mode on the MAC if not yet enabled.
787 		 */
788 		if (ptype == MAC_PROMISC && mip->mi_promisc++ == 0)
789 			i_mac_notify(mip, MAC_NOTE_PROMISC);
790 	} else {
791 		if (mip->mi_devpromisc == 0) {
792 			err = EPROTO;
793 			goto done;
794 		}
795 
796 		/*
797 		 * Disable promiscuous mode on the device if this is the last
798 		 * enabling.
799 		 */
800 		if (--mip->mi_devpromisc == 0) {
801 			if ((err = mp->m_promisc(mp->m_driver, B_FALSE)) != 0) {
802 				mip->mi_devpromisc++;
803 				goto done;
804 			}
805 			i_mac_notify(mip, MAC_NOTE_DEVPROMISC);
806 		}
807 
808 		/*
809 		 * Disable promiscuous mode on the MAC if this is the last
810 		 * enabling.
811 		 */
812 		if (ptype == MAC_PROMISC && --mip->mi_promisc == 0)
813 			i_mac_notify(mip, MAC_NOTE_PROMISC);
814 	}
815 
816 done:
817 	rw_exit(&(mip->mi_data_lock));
818 	return (err);
819 }
820 
821 boolean_t
822 mac_promisc_get(mac_handle_t mh, mac_promisc_type_t ptype)
823 {
824 	mac_impl_t		*mip = (mac_impl_t *)mh;
825 
826 	ASSERT(ptype == MAC_DEVPROMISC || ptype == MAC_PROMISC);
827 
828 	/*
829 	 * Return the current promiscuity.
830 	 */
831 	if (ptype == MAC_DEVPROMISC)
832 		return (mip->mi_devpromisc != 0);
833 	else
834 		return (mip->mi_promisc != 0);
835 }
836 
837 void
838 mac_resources(mac_handle_t mh)
839 {
840 	mac_impl_t	*mip = (mac_impl_t *)mh;
841 	mac_t		*mp = mip->mi_mp;
842 
843 	ASSERT(mp->m_resources != NULL);
844 
845 	/*
846 	 * Call the driver to register its resources.
847 	 */
848 	mp->m_resources(mp->m_driver);
849 }
850 
851 void
852 mac_ioctl(mac_handle_t mh, queue_t *wq, mblk_t *bp)
853 {
854 	mac_impl_t	*mip = (mac_impl_t *)mh;
855 	mac_t		*mp = mip->mi_mp;
856 
857 	ASSERT(mp->m_ioctl != NULL);
858 
859 	/*
860 	 * Call the driver to handle the ioctl.
861 	 */
862 	mp->m_ioctl(mp->m_driver, wq, bp);
863 }
864 
865 const mac_txinfo_t *
866 mac_tx_get(mac_handle_t mh)
867 {
868 	mac_impl_t	*mip = (mac_impl_t *)mh;
869 	mac_txinfo_t	*mtp;
870 
871 	/*
872 	 * Grab the lock to prevent us from racing with MAC_PROMISC being
873 	 * changed.  This is sufficient since MAC clients are careful to always
874 	 * call mac_txloop_add() prior to enabling MAC_PROMISC, and to disable
875 	 * MAC_PROMISC prior to calling mac_txloop_remove().
876 	 */
877 	rw_enter(&mip->mi_txloop_lock, RW_READER);
878 
879 	if (mac_promisc_get(mh, MAC_PROMISC)) {
880 		ASSERT(mip->mi_mtfp != NULL);
881 		mtp = &mip->mi_txloopinfo;
882 	} else {
883 		/*
884 		 * Note that we cannot ASSERT() that mip->mi_mtfp is NULL,
885 		 * because to satisfy the above ASSERT(), we have to disable
886 		 * MAC_PROMISC prior to calling mac_txloop_remove().
887 		 */
888 		mtp = &mip->mi_txinfo;
889 
890 	}
891 
892 	rw_exit(&mip->mi_txloop_lock);
893 	return (mtp);
894 }
895 
896 link_state_t
897 mac_link_get(mac_handle_t mh)
898 {
899 	mac_impl_t	*mip = (mac_impl_t *)mh;
900 
901 	/*
902 	 * Return the current link state.
903 	 */
904 	return (mip->mi_link);
905 }
906 
907 mac_notify_handle_t
908 mac_notify_add(mac_handle_t mh, mac_notify_t notify, void *arg)
909 {
910 	mac_impl_t		*mip = (mac_impl_t *)mh;
911 	mac_notify_fn_t		*mnfp;
912 
913 	mnfp = kmem_zalloc(sizeof (mac_notify_fn_t), KM_SLEEP);
914 	mnfp->mnf_fn = notify;
915 	mnfp->mnf_arg = arg;
916 
917 	/*
918 	 * Add it to the head of the 'notify' callback list.
919 	 */
920 	rw_enter(&mip->mi_notify_lock, RW_WRITER);
921 	mnfp->mnf_nextp = mip->mi_mnfp;
922 	mip->mi_mnfp = mnfp;
923 	rw_exit(&mip->mi_notify_lock);
924 
925 	return ((mac_notify_handle_t)mnfp);
926 }
927 
928 void
929 mac_notify_remove(mac_handle_t mh, mac_notify_handle_t mnh)
930 {
931 	mac_impl_t		*mip = (mac_impl_t *)mh;
932 	mac_notify_fn_t		*mnfp = (mac_notify_fn_t *)mnh;
933 	mac_notify_fn_t		**pp;
934 	mac_notify_fn_t		*p;
935 
936 	/*
937 	 * Search the 'notify' callback list for the function closure.
938 	 */
939 	rw_enter(&mip->mi_notify_lock, RW_WRITER);
940 	for (pp = &(mip->mi_mnfp); (p = *pp) != NULL;
941 	    pp = &(p->mnf_nextp)) {
942 		if (p == mnfp)
943 			break;
944 	}
945 	ASSERT(p != NULL);
946 
947 	/*
948 	 * Remove it from the list.
949 	 */
950 	*pp = p->mnf_nextp;
951 	rw_exit(&mip->mi_notify_lock);
952 
953 	/*
954 	 * Free it.
955 	 */
956 	kmem_free(mnfp, sizeof (mac_notify_fn_t));
957 }
958 
959 void
960 mac_notify(mac_handle_t mh)
961 {
962 	mac_impl_t		*mip = (mac_impl_t *)mh;
963 	mac_notify_type_t	type;
964 
965 	for (type = 0; type < MAC_NNOTE; type++)
966 		i_mac_notify(mip, type);
967 }
968 
969 mac_rx_handle_t
970 mac_rx_add(mac_handle_t mh, mac_rx_t rx, void *arg)
971 {
972 	mac_impl_t	*mip = (mac_impl_t *)mh;
973 	mac_rx_fn_t	*mrfp;
974 
975 	mrfp = kmem_zalloc(sizeof (mac_rx_fn_t), KM_SLEEP);
976 	mrfp->mrf_fn = rx;
977 	mrfp->mrf_arg = arg;
978 
979 	/*
980 	 * Add it to the head of the 'rx' callback list.
981 	 */
982 	rw_enter(&(mip->mi_rx_lock), RW_WRITER);
983 	mrfp->mrf_nextp = mip->mi_mrfp;
984 	mip->mi_mrfp = mrfp;
985 	rw_exit(&(mip->mi_rx_lock));
986 
987 	return ((mac_rx_handle_t)mrfp);
988 }
989 
990 /*
991  * Unregister a receive function for this mac.  This removes the function
992  * from the list of receive functions for this mac.
993  */
994 void
995 mac_rx_remove(mac_handle_t mh, mac_rx_handle_t mrh)
996 {
997 	mac_impl_t		*mip = (mac_impl_t *)mh;
998 	mac_rx_fn_t		*mrfp = (mac_rx_fn_t *)mrh;
999 	mac_rx_fn_t		**pp;
1000 	mac_rx_fn_t		*p;
1001 
1002 	/*
1003 	 * Search the 'rx' callback list for the function closure.
1004 	 */
1005 	rw_enter(&(mip->mi_rx_lock), RW_WRITER);
1006 	for (pp = &(mip->mi_mrfp); (p = *pp) != NULL; pp = &(p->mrf_nextp)) {
1007 		if (p == mrfp)
1008 			break;
1009 	}
1010 	ASSERT(p != NULL);
1011 
1012 	/* Remove it from the list. */
1013 	*pp = p->mrf_nextp;
1014 	kmem_free(mrfp, sizeof (mac_rx_fn_t));
1015 	rw_exit(&(mip->mi_rx_lock));
1016 }
1017 
1018 mac_txloop_handle_t
1019 mac_txloop_add(mac_handle_t mh, mac_txloop_t tx, void *arg)
1020 {
1021 	mac_impl_t	*mip = (mac_impl_t *)mh;
1022 	mac_txloop_fn_t	*mtfp;
1023 
1024 	mtfp = kmem_zalloc(sizeof (mac_txloop_fn_t), KM_SLEEP);
1025 	mtfp->mtf_fn = tx;
1026 	mtfp->mtf_arg = arg;
1027 
1028 	/*
1029 	 * Add it to the head of the 'tx' callback list.
1030 	 */
1031 	rw_enter(&(mip->mi_txloop_lock), RW_WRITER);
1032 	mtfp->mtf_nextp = mip->mi_mtfp;
1033 	mip->mi_mtfp = mtfp;
1034 	rw_exit(&(mip->mi_txloop_lock));
1035 
1036 	return ((mac_txloop_handle_t)mtfp);
1037 }
1038 
1039 /*
1040  * Unregister a transmit function for this mac.  This removes the function
1041  * from the list of transmit functions for this mac.
1042  */
1043 void
1044 mac_txloop_remove(mac_handle_t mh, mac_txloop_handle_t mth)
1045 {
1046 	mac_impl_t		*mip = (mac_impl_t *)mh;
1047 	mac_txloop_fn_t		*mtfp = (mac_txloop_fn_t *)mth;
1048 	mac_txloop_fn_t		**pp;
1049 	mac_txloop_fn_t		*p;
1050 
1051 	/*
1052 	 * Search the 'tx' callback list for the function.
1053 	 */
1054 	rw_enter(&(mip->mi_txloop_lock), RW_WRITER);
1055 	for (pp = &(mip->mi_mtfp); (p = *pp) != NULL; pp = &(p->mtf_nextp)) {
1056 		if (p == mtfp)
1057 			break;
1058 	}
1059 	ASSERT(p != NULL);
1060 
1061 	/* Remove it from the list. */
1062 	*pp = p->mtf_nextp;
1063 	kmem_free(mtfp, sizeof (mac_txloop_fn_t));
1064 	rw_exit(&(mip->mi_txloop_lock));
1065 }
1066 
1067 void
1068 mac_resource_set(mac_handle_t mh, mac_resource_add_t add, void *arg)
1069 {
1070 	mac_impl_t		*mip = (mac_impl_t *)mh;
1071 
1072 	/*
1073 	 * Update the 'resource_add' callbacks.
1074 	 */
1075 	rw_enter(&(mip->mi_resource_lock), RW_WRITER);
1076 	mip->mi_resource_add = add;
1077 	mip->mi_resource_add_arg = arg;
1078 	rw_exit(&(mip->mi_resource_lock));
1079 }
1080 
1081 /*
1082  * Driver support functions.
1083  */
1084 
1085 int
1086 mac_register(mac_t *mp)
1087 {
1088 	int	err, instance;
1089 	char	name[MAXNAMELEN], devname[MAXNAMELEN];
1090 	const char *drvname;
1091 	struct devnames *dnp;
1092 	minor_t	minor;
1093 
1094 	drvname = ddi_driver_name(mp->m_dip);
1095 	instance = ddi_get_instance(mp->m_dip);
1096 
1097 	if (strcmp(mp->m_ident, MAC_IDENT) != 0) {
1098 		cmn_err(CE_WARN, "%s%d/%d: possible mac interface mismatch",
1099 		    drvname, instance, mp->m_port);
1100 	}
1101 
1102 	/*
1103 	 * Create a new mac_impl_t to pair with the mac_t.
1104 	 */
1105 	if ((err = i_mac_create(mp)) != 0)
1106 		return (err);
1107 
1108 	err = EEXIST;
1109 	if (ddi_create_minor_node(mp->m_dip, (char *)drvname, S_IFCHR, 0,
1110 	    DDI_NT_NET, CLONE_DEV) != DDI_SUCCESS)
1111 		goto fail1;
1112 
1113 	(void) snprintf(devname, MAXNAMELEN, "%s%d", drvname, instance);
1114 
1115 	if (strcmp(drvname, "aggr") == 0) {
1116 		(void) snprintf(name, MAXNAMELEN, "aggr%u", mp->m_port);
1117 		minor = (minor_t)mp->m_port + 1;
1118 	} else {
1119 		(void) strlcpy(name, devname, MAXNAMELEN);
1120 		minor = (minor_t)instance + 1;
1121 	}
1122 
1123 	if (ddi_create_minor_node(mp->m_dip, name, S_IFCHR, minor,
1124 	    DDI_NT_NET, 0) != DDI_SUCCESS)
1125 		goto fail2;
1126 
1127 	if ((err = dls_create(name, devname, mp->m_port)) != 0)
1128 		goto fail3;
1129 
1130 	/* set the gldv3 flag in dn_flags */
1131 	dnp = &devnamesp[ddi_driver_major(mp->m_dip)];
1132 	LOCK_DEV_OPS(&dnp->dn_lock);
1133 	dnp->dn_flags |= DN_GLDV3_DRIVER;
1134 	UNLOCK_DEV_OPS(&dnp->dn_lock);
1135 
1136 	/*
1137 	 * Mark the MAC to be ready for open.
1138 	 */
1139 	rw_enter(&i_mac_impl_lock, RW_WRITER);
1140 	((mac_impl_t *)mp->m_impl)->mi_disabled = B_FALSE;
1141 	rw_exit(&i_mac_impl_lock);
1142 
1143 	cmn_err(CE_NOTE, "!%s%d/%d registered", drvname, instance, mp->m_port);
1144 	return (0);
1145 
1146 fail3:
1147 	ddi_remove_minor_node(mp->m_dip, name);
1148 fail2:
1149 	ddi_remove_minor_node(mp->m_dip, (char *)drvname);
1150 fail1:
1151 	i_mac_destroy(mp);
1152 	return (err);
1153 }
1154 
1155 int
1156 mac_unregister(mac_t *mp)
1157 {
1158 	int		err, instance;
1159 	char		name[MAXNAMELEN];
1160 	const char	*drvname;
1161 	mac_impl_t	*mip = mp->m_impl;
1162 
1163 	drvname = ddi_driver_name(mp->m_dip);
1164 	instance = ddi_get_instance(mp->m_dip);
1165 
1166 	/*
1167 	 * See if there are any other references to this mac_t (e.g., VLAN's).
1168 	 * If not, set mi_disabled to prevent any new VLAN's from being
1169 	 * created before we can perform the i_mac_destroy() below.
1170 	 */
1171 	rw_enter(&i_mac_impl_lock, RW_WRITER);
1172 	if (mip->mi_ref > 0) {
1173 		rw_exit(&i_mac_impl_lock);
1174 		return (EBUSY);
1175 	}
1176 	mip->mi_disabled = B_TRUE;
1177 	rw_exit(&i_mac_impl_lock);
1178 
1179 	/*
1180 	 * Wait for all taskqs which process the mac notifications to finish.
1181 	 */
1182 	mutex_enter(&mip->mi_notify_ref_lock);
1183 	while (mip->mi_notify_ref != 0)
1184 		cv_wait(&mip->mi_notify_cv, &mip->mi_notify_ref_lock);
1185 	mutex_exit(&mip->mi_notify_ref_lock);
1186 
1187 	if (strcmp(drvname, "aggr") == 0)
1188 		(void) snprintf(name, MAXNAMELEN, "aggr%u", mp->m_port);
1189 	else
1190 		(void) snprintf(name, MAXNAMELEN, "%s%d", drvname, instance);
1191 
1192 	if ((err = dls_destroy(name)) != 0) {
1193 		rw_enter(&i_mac_impl_lock, RW_WRITER);
1194 		mip->mi_disabled = B_FALSE;
1195 		rw_exit(&i_mac_impl_lock);
1196 		return (err);
1197 	}
1198 
1199 	/*
1200 	 * Destroy the mac_impl_t.
1201 	 */
1202 	i_mac_destroy(mp);
1203 
1204 	/*
1205 	 * Remove both style 1 and style 2 minor nodes
1206 	 */
1207 	ddi_remove_minor_node(mp->m_dip, (char *)drvname);
1208 	ddi_remove_minor_node(mp->m_dip, name);
1209 
1210 	cmn_err(CE_NOTE, "!%s%d/%d unregistered", drvname, instance,
1211 	    mp->m_port);
1212 	return (0);
1213 }
1214 
1215 void
1216 mac_rx(mac_t *mp, mac_resource_handle_t mrh, mblk_t *bp)
1217 {
1218 	mac_impl_t	*mip = mp->m_impl;
1219 	mac_rx_fn_t	*mrfp;
1220 
1221 	/*
1222 	 * Call all registered receive functions.
1223 	 */
1224 	rw_enter(&mip->mi_rx_lock, RW_READER);
1225 	mrfp = mip->mi_mrfp;
1226 	if (mrfp == NULL) {
1227 		/* There are no registered receive functions. */
1228 		freemsgchain(bp);
1229 		rw_exit(&mip->mi_rx_lock);
1230 		return;
1231 	}
1232 	do {
1233 		mblk_t *recv_bp;
1234 
1235 		if (mrfp->mrf_nextp != NULL) {
1236 			/* XXX Do we bump a counter if copymsgchain() fails? */
1237 			recv_bp = copymsgchain(bp);
1238 		} else {
1239 			recv_bp = bp;
1240 		}
1241 		if (recv_bp != NULL)
1242 			mrfp->mrf_fn(mrfp->mrf_arg, mrh, recv_bp);
1243 		mrfp = mrfp->mrf_nextp;
1244 	} while (mrfp != NULL);
1245 	rw_exit(&mip->mi_rx_lock);
1246 }
1247 
1248 /*
1249  * Transmit function -- ONLY used when there are registered loopback listeners.
1250  */
1251 mblk_t *
1252 mac_txloop(void *arg, mblk_t *bp)
1253 {
1254 	mac_impl_t	*mip = arg;
1255 	mac_t		*mp = mip->mi_mp;
1256 	mac_txloop_fn_t	*mtfp;
1257 	mblk_t		*loop_bp, *resid_bp, *next_bp;
1258 
1259 	while (bp != NULL) {
1260 		next_bp = bp->b_next;
1261 		bp->b_next = NULL;
1262 
1263 		if ((loop_bp = copymsg(bp)) == NULL)
1264 			goto noresources;
1265 
1266 		if ((resid_bp = mp->m_tx(mp->m_driver, bp)) != NULL) {
1267 			ASSERT(resid_bp == bp);
1268 			freemsg(loop_bp);
1269 			goto noresources;
1270 		}
1271 
1272 		rw_enter(&mip->mi_txloop_lock, RW_READER);
1273 		mtfp = mip->mi_mtfp;
1274 		while (mtfp != NULL && loop_bp != NULL) {
1275 			bp = loop_bp;
1276 
1277 			/* XXX counter bump if copymsg() fails? */
1278 			if (mtfp->mtf_nextp != NULL)
1279 				loop_bp = copymsg(bp);
1280 			else
1281 				loop_bp = NULL;
1282 
1283 			mtfp->mtf_fn(mtfp->mtf_arg, bp);
1284 			mtfp = mtfp->mtf_nextp;
1285 		}
1286 		rw_exit(&mip->mi_txloop_lock);
1287 
1288 		/*
1289 		 * It's possible we've raced with the disabling of promiscuous
1290 		 * mode, in which case we can discard our copy.
1291 		 */
1292 		if (loop_bp != NULL)
1293 			freemsg(loop_bp);
1294 
1295 		bp = next_bp;
1296 	}
1297 
1298 	return (NULL);
1299 
1300 noresources:
1301 	bp->b_next = next_bp;
1302 	return (bp);
1303 }
1304 
1305 void
1306 mac_link_update(mac_t *mp, link_state_t link)
1307 {
1308 	mac_impl_t	*mip = mp->m_impl;
1309 
1310 	ASSERT(mip->mi_mp == mp);
1311 
1312 	/*
1313 	 * Save the link state.
1314 	 */
1315 	mip->mi_link = link;
1316 
1317 	/*
1318 	 * Send a MAC_NOTE_LINK notification.
1319 	 */
1320 	i_mac_notify(mip, MAC_NOTE_LINK);
1321 }
1322 
1323 void
1324 mac_unicst_update(mac_t *mp, const uint8_t *addr)
1325 {
1326 	mac_impl_t	*mip = mp->m_impl;
1327 
1328 	ASSERT(mip->mi_mp == mp);
1329 
1330 	/*
1331 	 * Save the address.
1332 	 */
1333 	bcopy(addr, mip->mi_addr, mip->mi_addr_length);
1334 
1335 	/*
1336 	 * Send a MAC_NOTE_UNICST notification.
1337 	 */
1338 	i_mac_notify(mip, MAC_NOTE_UNICST);
1339 }
1340 
1341 void
1342 mac_tx_update(mac_t *mp)
1343 {
1344 	mac_impl_t	*mip = mp->m_impl;
1345 
1346 	ASSERT(mip->mi_mp == mp);
1347 
1348 	/*
1349 	 * Send a MAC_NOTE_TX notification.
1350 	 */
1351 	i_mac_notify(mip, MAC_NOTE_TX);
1352 }
1353 
1354 void
1355 mac_resource_update(mac_t *mp)
1356 {
1357 	mac_impl_t	*mip = mp->m_impl;
1358 
1359 	ASSERT(mip->mi_mp == mp);
1360 
1361 	/*
1362 	 * Send a MAC_NOTE_RESOURCE notification.
1363 	 */
1364 	i_mac_notify(mip, MAC_NOTE_RESOURCE);
1365 }
1366 
1367 mac_resource_handle_t
1368 mac_resource_add(mac_t *mp, mac_resource_t *mrp)
1369 {
1370 	mac_impl_t		*mip = mp->m_impl;
1371 	mac_resource_handle_t	mrh;
1372 	mac_resource_add_t	add;
1373 	void			*arg;
1374 
1375 	rw_enter(&mip->mi_resource_lock, RW_READER);
1376 	add = mip->mi_resource_add;
1377 	arg = mip->mi_resource_add_arg;
1378 
1379 	if (add != NULL)
1380 		mrh = add(arg, mrp);
1381 	else
1382 		mrh = NULL;
1383 	rw_exit(&mip->mi_resource_lock);
1384 
1385 	return (mrh);
1386 }
1387 
1388 void
1389 mac_multicst_refresh(mac_t *mp, mac_multicst_t refresh, void *arg,
1390     boolean_t add)
1391 {
1392 	mac_impl_t		*mip = mp->m_impl;
1393 	mac_multicst_addr_t	*p;
1394 
1395 	/*
1396 	 * If no specific refresh function was given then default to the
1397 	 * driver's m_multicst entry point.
1398 	 */
1399 	if (refresh == NULL) {
1400 		refresh = mp->m_multicst;
1401 		arg = mp->m_driver;
1402 	}
1403 	ASSERT(refresh != NULL);
1404 
1405 	/*
1406 	 * Walk the multicast address list and call the refresh function for
1407 	 * each address.
1408 	 */
1409 	rw_enter(&(mip->mi_data_lock), RW_READER);
1410 	for (p = mip->mi_mmap; p != NULL; p = p->mma_nextp)
1411 		refresh(arg, add, p->mma_addr);
1412 	rw_exit(&(mip->mi_data_lock));
1413 }
1414 
1415 void
1416 mac_unicst_refresh(mac_t *mp, mac_unicst_t refresh, void *arg)
1417 {
1418 	mac_impl_t	*mip = mp->m_impl;
1419 	/*
1420 	 * If no specific refresh function was given then default to the
1421 	 * driver's m_unicst entry point.
1422 	 */
1423 	if (refresh == NULL) {
1424 		refresh = mp->m_unicst;
1425 		arg = mp->m_driver;
1426 	}
1427 	ASSERT(refresh != NULL);
1428 
1429 	/*
1430 	 * Call the refresh function with the current unicast address.
1431 	 */
1432 	refresh(arg, mip->mi_addr);
1433 }
1434 
1435 void
1436 mac_promisc_refresh(mac_t *mp, mac_promisc_t refresh, void *arg)
1437 {
1438 	mac_impl_t	*mip = mp->m_impl;
1439 
1440 	/*
1441 	 * If no specific refresh function was given then default to the
1442 	 * driver's m_promisc entry point.
1443 	 */
1444 	if (refresh == NULL) {
1445 		refresh = mp->m_promisc;
1446 		arg = mp->m_driver;
1447 	}
1448 	ASSERT(refresh != NULL);
1449 
1450 	/*
1451 	 * Call the refresh function with the current promiscuity.
1452 	 */
1453 	refresh(arg, (mip->mi_devpromisc != 0));
1454 }
1455 
1456 boolean_t
1457 mac_active_set(mac_handle_t mh)
1458 {
1459 	mac_impl_t *mip = (mac_impl_t *)mh;
1460 
1461 	mutex_enter(&mip->mi_activelink_lock);
1462 	if (mip->mi_activelink) {
1463 		mutex_exit(&mip->mi_activelink_lock);
1464 		return (B_FALSE);
1465 	}
1466 	mip->mi_activelink = B_TRUE;
1467 	mutex_exit(&mip->mi_activelink_lock);
1468 	return (B_TRUE);
1469 }
1470 
1471 void
1472 mac_active_clear(mac_handle_t mh)
1473 {
1474 	mac_impl_t *mip = (mac_impl_t *)mh;
1475 
1476 	mutex_enter(&mip->mi_activelink_lock);
1477 	ASSERT(mip->mi_activelink);
1478 	mip->mi_activelink = B_FALSE;
1479 	mutex_exit(&mip->mi_activelink_lock);
1480 }
1481 
1482 /*
1483  * mac_info_get() is used for retrieving the mac_info when a DL_INFO_REQ is
1484  * issued before a DL_ATTACH_REQ. we walk the i_mac_impl_hash table and find
1485  * the first mac_impl_t with a matching driver name; then we copy its mac_info_t
1486  * to the caller. we do all this with i_mac_impl_lock held so the mac_impl_t
1487  * cannot disappear while we are accessing it.
1488  */
1489 typedef struct i_mac_info_state_s {
1490 	const char	*mi_name;
1491 	mac_info_t	*mi_infop;
1492 } i_mac_info_state_t;
1493 
1494 /*ARGSUSED*/
1495 static uint_t
1496 i_mac_info_walker(mod_hash_key_t key, mod_hash_val_t *val, void *arg)
1497 {
1498 	i_mac_info_state_t	*statep = arg;
1499 	mac_impl_t		*mip = (mac_impl_t *)val;
1500 
1501 	if (mip->mi_disabled)
1502 		return (MH_WALK_CONTINUE);
1503 
1504 	if (strcmp(statep->mi_name,
1505 	    ddi_driver_name(mip->mi_mp->m_dip)) != 0)
1506 		return (MH_WALK_CONTINUE);
1507 
1508 	statep->mi_infop = &mip->mi_mp->m_info;
1509 	return (MH_WALK_TERMINATE);
1510 }
1511 
1512 boolean_t
1513 mac_info_get(const char *name, mac_info_t *minfop)
1514 {
1515 	i_mac_info_state_t	state;
1516 
1517 	rw_enter(&i_mac_impl_lock, RW_READER);
1518 	state.mi_name = name;
1519 	state.mi_infop = NULL;
1520 	mod_hash_walk(i_mac_impl_hash, i_mac_info_walker, &state);
1521 	if (state.mi_infop == NULL) {
1522 		rw_exit(&i_mac_impl_lock);
1523 		return (B_FALSE);
1524 	}
1525 	*minfop = *state.mi_infop;
1526 	rw_exit(&i_mac_impl_lock);
1527 	return (B_TRUE);
1528 }
1529 
1530 void
1531 mac_init_ops(struct dev_ops *ops, const char *name)
1532 {
1533 	dld_init_ops(ops, name);
1534 }
1535 
1536 void
1537 mac_fini_ops(struct dev_ops *ops)
1538 {
1539 	dld_fini_ops(ops);
1540 }
1541