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