xref: /titanic_52/usr/src/uts/common/io/mac/mac.c (revision d51e90740114c60620c0febffd4d3ce6e280a107)
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 #include <sys/modctl.h>
45 #include <sys/atomic.h>
46 
47 #define	IMPL_HASHSZ	67	/* prime */
48 
49 static kmem_cache_t	*i_mac_impl_cachep;
50 static mod_hash_t	*i_mac_impl_hash;
51 krwlock_t		i_mac_impl_lock;
52 uint_t			i_mac_impl_count;
53 
54 #define	MACTYPE_KMODDIR	"mac"
55 #define	MACTYPE_HASHSZ	67
56 static mod_hash_t	*i_mactype_hash;
57 /*
58  * i_mactype_lock synchronizes threads that obtain references to mactype_t
59  * structures through i_mactype_getplugin().
60  */
61 static kmutex_t		i_mactype_lock;
62 
63 static void i_mac_notify_task(void *);
64 
65 /*
66  * Private functions.
67  */
68 
69 /*ARGSUSED*/
70 static int
71 i_mac_constructor(void *buf, void *arg, int kmflag)
72 {
73 	mac_impl_t	*mip = buf;
74 
75 	bzero(buf, sizeof (mac_impl_t));
76 
77 	mip->mi_linkstate = LINK_STATE_UNKNOWN;
78 
79 	rw_init(&mip->mi_state_lock, NULL, RW_DRIVER, NULL);
80 	rw_init(&mip->mi_data_lock, NULL, RW_DRIVER, NULL);
81 	rw_init(&mip->mi_notify_lock, NULL, RW_DRIVER, NULL);
82 	rw_init(&mip->mi_rx_lock, NULL, RW_DRIVER, NULL);
83 	rw_init(&mip->mi_txloop_lock, NULL, RW_DRIVER, NULL);
84 	rw_init(&mip->mi_resource_lock, NULL, RW_DRIVER, NULL);
85 	mutex_init(&mip->mi_activelink_lock, NULL, MUTEX_DEFAULT, NULL);
86 	mutex_init(&mip->mi_notify_ref_lock, NULL, MUTEX_DRIVER, NULL);
87 	cv_init(&mip->mi_notify_cv, NULL, CV_DRIVER, NULL);
88 	return (0);
89 }
90 
91 /*ARGSUSED*/
92 static void
93 i_mac_destructor(void *buf, void *arg)
94 {
95 	mac_impl_t	*mip = buf;
96 
97 	ASSERT(mip->mi_ref == 0);
98 	ASSERT(mip->mi_active == 0);
99 	ASSERT(mip->mi_linkstate == LINK_STATE_UNKNOWN);
100 	ASSERT(mip->mi_devpromisc == 0);
101 	ASSERT(mip->mi_promisc == 0);
102 	ASSERT(mip->mi_mmap == NULL);
103 	ASSERT(mip->mi_mnfp == NULL);
104 	ASSERT(mip->mi_resource_add == NULL);
105 	ASSERT(mip->mi_ksp == NULL);
106 	ASSERT(mip->mi_kstat_count == 0);
107 
108 	rw_destroy(&mip->mi_state_lock);
109 	rw_destroy(&mip->mi_data_lock);
110 	rw_destroy(&mip->mi_notify_lock);
111 	rw_destroy(&mip->mi_rx_lock);
112 	rw_destroy(&mip->mi_txloop_lock);
113 	rw_destroy(&mip->mi_resource_lock);
114 	mutex_destroy(&mip->mi_activelink_lock);
115 	mutex_destroy(&mip->mi_notify_ref_lock);
116 	cv_destroy(&mip->mi_notify_cv);
117 }
118 
119 static void
120 i_mac_notify(mac_impl_t *mip, mac_notify_type_t type)
121 {
122 	mac_notify_task_arg_t	*mnta;
123 
124 	rw_enter(&i_mac_impl_lock, RW_READER);
125 	if (mip->mi_disabled)
126 		goto exit;
127 
128 	if ((mnta = kmem_alloc(sizeof (*mnta), KM_NOSLEEP)) == NULL) {
129 		cmn_err(CE_WARN, "i_mac_notify(%s, 0x%x): memory "
130 		    "allocation failed", mip->mi_name, type);
131 		goto exit;
132 	}
133 
134 	mnta->mnt_mip = mip;
135 	mnta->mnt_type = type;
136 
137 	mutex_enter(&mip->mi_notify_ref_lock);
138 	mip->mi_notify_ref++;
139 	mutex_exit(&mip->mi_notify_ref_lock);
140 
141 	rw_exit(&i_mac_impl_lock);
142 
143 	if (taskq_dispatch(system_taskq, i_mac_notify_task, mnta,
144 	    TQ_NOSLEEP) == NULL) {
145 		cmn_err(CE_WARN, "i_mac_notify(%s, 0x%x): taskq dispatch "
146 		    "failed", mip->mi_name, type);
147 
148 		mutex_enter(&mip->mi_notify_ref_lock);
149 		if (--mip->mi_notify_ref == 0)
150 			cv_signal(&mip->mi_notify_cv);
151 		mutex_exit(&mip->mi_notify_ref_lock);
152 
153 		kmem_free(mnta, sizeof (*mnta));
154 	}
155 	return;
156 
157 exit:
158 	rw_exit(&i_mac_impl_lock);
159 }
160 
161 static void
162 i_mac_notify_task(void *notify_arg)
163 {
164 	mac_notify_task_arg_t	*mnta = (mac_notify_task_arg_t *)notify_arg;
165 	mac_impl_t		*mip;
166 	mac_notify_type_t	type;
167 	mac_notify_fn_t		*mnfp;
168 	mac_notify_t		notify;
169 	void			*arg;
170 
171 	mip = mnta->mnt_mip;
172 	type = mnta->mnt_type;
173 	kmem_free(mnta, sizeof (*mnta));
174 
175 	/*
176 	 * Walk the list of notifications.
177 	 */
178 	rw_enter(&mip->mi_notify_lock, RW_READER);
179 	for (mnfp = mip->mi_mnfp; mnfp != NULL; mnfp = mnfp->mnf_nextp) {
180 		notify = mnfp->mnf_fn;
181 		arg = mnfp->mnf_arg;
182 
183 		ASSERT(notify != NULL);
184 		notify(arg, type);
185 	}
186 	rw_exit(&mip->mi_notify_lock);
187 	mutex_enter(&mip->mi_notify_ref_lock);
188 	if (--mip->mi_notify_ref == 0)
189 		cv_signal(&mip->mi_notify_cv);
190 	mutex_exit(&mip->mi_notify_ref_lock);
191 }
192 
193 static mactype_t *
194 i_mactype_getplugin(const char *pname)
195 {
196 	mactype_t	*mtype = NULL;
197 	boolean_t	tried_modload = B_FALSE;
198 
199 	mutex_enter(&i_mactype_lock);
200 
201 find_registered_mactype:
202 	if (mod_hash_find(i_mactype_hash, (mod_hash_key_t)pname,
203 	    (mod_hash_val_t *)&mtype) != 0) {
204 		if (!tried_modload) {
205 			/*
206 			 * If the plugin has not yet been loaded, then
207 			 * attempt to load it now.  If modload() succeeds,
208 			 * the plugin should have registered using
209 			 * mactype_register(), in which case we can go back
210 			 * and attempt to find it again.
211 			 */
212 			if (modload(MACTYPE_KMODDIR, (char *)pname) != -1) {
213 				tried_modload = B_TRUE;
214 				goto find_registered_mactype;
215 			}
216 		}
217 	} else {
218 		/*
219 		 * Note that there's no danger that the plugin we've loaded
220 		 * could be unloaded between the modload() step and the
221 		 * reference count bump here, as we're holding
222 		 * i_mactype_lock, which mactype_unregister() also holds.
223 		 */
224 		atomic_inc_32(&mtype->mt_ref);
225 	}
226 
227 	mutex_exit(&i_mactype_lock);
228 	return (mtype);
229 }
230 
231 /*
232  * Module initialization functions.
233  */
234 
235 void
236 mac_init(void)
237 {
238 	i_mac_impl_cachep = kmem_cache_create("mac_impl_cache",
239 	    sizeof (mac_impl_t), 0, i_mac_constructor, i_mac_destructor,
240 	    NULL, NULL, NULL, 0);
241 	ASSERT(i_mac_impl_cachep != NULL);
242 
243 	i_mac_impl_hash = mod_hash_create_extended("mac_impl_hash",
244 	    IMPL_HASHSZ, mod_hash_null_keydtor, mod_hash_null_valdtor,
245 	    mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP);
246 	rw_init(&i_mac_impl_lock, NULL, RW_DEFAULT, NULL);
247 	i_mac_impl_count = 0;
248 
249 	i_mactype_hash = mod_hash_create_extended("mactype_hash",
250 	    MACTYPE_HASHSZ,
251 	    mod_hash_null_keydtor, mod_hash_null_valdtor,
252 	    mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP);
253 }
254 
255 int
256 mac_fini(void)
257 {
258 	if (i_mac_impl_count > 0)
259 		return (EBUSY);
260 
261 	mod_hash_destroy_hash(i_mac_impl_hash);
262 	rw_destroy(&i_mac_impl_lock);
263 
264 	kmem_cache_destroy(i_mac_impl_cachep);
265 
266 	mod_hash_destroy_hash(i_mactype_hash);
267 	return (0);
268 }
269 
270 /*
271  * Client functions.
272  */
273 
274 int
275 mac_open(const char *macname, uint_t ddi_instance, mac_handle_t *mhp)
276 {
277 	char		driver[MAXNAMELEN];
278 	uint_t		instance;
279 	major_t		major;
280 	dev_info_t	*dip;
281 	mac_impl_t	*mip;
282 	int		err;
283 
284 	/*
285 	 * Check the device name length to make sure it won't overflow our
286 	 * buffer.
287 	 */
288 	if (strlen(macname) >= MAXNAMELEN)
289 		return (EINVAL);
290 
291 	/*
292 	 * Split the device name into driver and instance components.
293 	 */
294 	if (ddi_parse(macname, driver, &instance) != DDI_SUCCESS)
295 		return (EINVAL);
296 
297 	/*
298 	 * Get the major number of the driver.
299 	 */
300 	if ((major = ddi_name_to_major(driver)) == (major_t)-1)
301 		return (EINVAL);
302 
303 	/*
304 	 * Hold the given instance to prevent it from being detached.
305 	 * This will also attach the instance if it is not currently attached.
306 	 * Currently we ensure that mac_register() (called by the driver's
307 	 * attach entry point) and all code paths under it cannot possibly
308 	 * call mac_open() because this would lead to a recursive attach
309 	 * panic.
310 	 */
311 	if ((dip = ddi_hold_devi_by_instance(major, ddi_instance, 0)) == NULL)
312 		return (EINVAL);
313 
314 	/*
315 	 * Look up its entry in the global hash table.
316 	 */
317 again:
318 	rw_enter(&i_mac_impl_lock, RW_WRITER);
319 	err = mod_hash_find(i_mac_impl_hash, (mod_hash_key_t)macname,
320 	    (mod_hash_val_t *)&mip);
321 	if (err != 0) {
322 		err = ENOENT;
323 		goto failed;
324 	}
325 
326 	if (mip->mi_disabled) {
327 		rw_exit(&i_mac_impl_lock);
328 		goto again;
329 	}
330 
331 	mip->mi_ref++;
332 	rw_exit(&i_mac_impl_lock);
333 
334 	*mhp = (mac_handle_t)mip;
335 	return (0);
336 
337 failed:
338 	rw_exit(&i_mac_impl_lock);
339 	ddi_release_devi(dip);
340 	return (err);
341 }
342 
343 void
344 mac_close(mac_handle_t mh)
345 {
346 	mac_impl_t	*mip = (mac_impl_t *)mh;
347 	dev_info_t	*dip = mip->mi_dip;
348 
349 	rw_enter(&i_mac_impl_lock, RW_WRITER);
350 
351 	ASSERT(mip->mi_ref != 0);
352 	if (--mip->mi_ref == 0) {
353 		ASSERT(!mip->mi_activelink);
354 	}
355 	ddi_release_devi(dip);
356 	rw_exit(&i_mac_impl_lock);
357 }
358 
359 const mac_info_t *
360 mac_info(mac_handle_t mh)
361 {
362 	return (&((mac_impl_t *)mh)->mi_info);
363 }
364 
365 dev_info_t *
366 mac_devinfo_get(mac_handle_t mh)
367 {
368 	return (((mac_impl_t *)mh)->mi_dip);
369 }
370 
371 uint64_t
372 mac_stat_get(mac_handle_t mh, uint_t stat)
373 {
374 	mac_impl_t	*mip = (mac_impl_t *)mh;
375 	uint64_t	val;
376 	int		ret;
377 
378 	/*
379 	 * The range of stat determines where it is maintained.  Stat
380 	 * values from 0 up to (but not including) MAC_STAT_MIN are
381 	 * mainteined by the mac module itself.  Everything else is
382 	 * maintained by the driver.
383 	 */
384 	if (stat < MAC_STAT_MIN) {
385 		/* These stats are maintained by the mac module itself. */
386 		switch (stat) {
387 		case MAC_STAT_LINK_STATE:
388 			return (mip->mi_linkstate);
389 		case MAC_STAT_LINK_UP:
390 			return (mip->mi_linkstate == LINK_STATE_UP);
391 		case MAC_STAT_PROMISC:
392 			return (mip->mi_devpromisc != 0);
393 		default:
394 			ASSERT(B_FALSE);
395 		}
396 	}
397 
398 	/*
399 	 * Call the driver to get the given statistic.
400 	 */
401 	ret = mip->mi_getstat(mip->mi_driver, stat, &val);
402 	if (ret != 0) {
403 		/*
404 		 * The driver doesn't support this statistic.  Get the
405 		 * statistic's default value.
406 		 */
407 		val = mac_stat_default(mip, stat);
408 	}
409 	return (val);
410 }
411 
412 int
413 mac_start(mac_handle_t mh)
414 {
415 	mac_impl_t	*mip = (mac_impl_t *)mh;
416 	int		err;
417 
418 	ASSERT(mip->mi_start != NULL);
419 
420 	rw_enter(&(mip->mi_state_lock), RW_WRITER);
421 
422 	/*
423 	 * Check whether the device is already started.
424 	 */
425 	if (mip->mi_active++ != 0) {
426 		/*
427 		 * It's already started so there's nothing more to do.
428 		 */
429 		err = 0;
430 		goto done;
431 	}
432 
433 	/*
434 	 * Start the device.
435 	 */
436 	if ((err = mip->mi_start(mip->mi_driver)) != 0)
437 		--mip->mi_active;
438 
439 done:
440 	rw_exit(&(mip->mi_state_lock));
441 	return (err);
442 }
443 
444 void
445 mac_stop(mac_handle_t mh)
446 {
447 	mac_impl_t	*mip = (mac_impl_t *)mh;
448 
449 	ASSERT(mip->mi_stop != NULL);
450 
451 	rw_enter(&(mip->mi_state_lock), RW_WRITER);
452 
453 	/*
454 	 * Check whether the device is still needed.
455 	 */
456 	ASSERT(mip->mi_active != 0);
457 	if (--mip->mi_active != 0) {
458 		/*
459 		 * It's still needed so there's nothing more to do.
460 		 */
461 		goto done;
462 	}
463 
464 	/*
465 	 * Stop the device.
466 	 */
467 	mip->mi_stop(mip->mi_driver);
468 
469 done:
470 	rw_exit(&(mip->mi_state_lock));
471 }
472 
473 int
474 mac_multicst_add(mac_handle_t mh, const uint8_t *addr)
475 {
476 	mac_impl_t		*mip = (mac_impl_t *)mh;
477 	mac_multicst_addr_t	**pp;
478 	mac_multicst_addr_t	*p;
479 	int			err;
480 
481 	ASSERT(mip->mi_multicst != NULL);
482 
483 	/*
484 	 * Verify the address.
485 	 */
486 	if ((err = mip->mi_type->mt_ops.mtops_multicst_verify(addr,
487 	    mip->mi_pdata)) != 0) {
488 		return (err);
489 	}
490 
491 	/*
492 	 * Check whether the given address is already enabled.
493 	 */
494 	rw_enter(&(mip->mi_data_lock), RW_WRITER);
495 	for (pp = &(mip->mi_mmap); (p = *pp) != NULL; pp = &(p->mma_nextp)) {
496 		if (bcmp(p->mma_addr, addr, mip->mi_type->mt_addr_length) ==
497 		    0) {
498 			/*
499 			 * The address is already enabled so just bump the
500 			 * reference count.
501 			 */
502 			p->mma_ref++;
503 			err = 0;
504 			goto done;
505 		}
506 	}
507 
508 	/*
509 	 * Allocate a new list entry.
510 	 */
511 	if ((p = kmem_zalloc(sizeof (mac_multicst_addr_t),
512 	    KM_NOSLEEP)) == NULL) {
513 		err = ENOMEM;
514 		goto done;
515 	}
516 
517 	/*
518 	 * Enable a new multicast address.
519 	 */
520 	if ((err = mip->mi_multicst(mip->mi_driver, B_TRUE, addr)) != 0) {
521 		kmem_free(p, sizeof (mac_multicst_addr_t));
522 		goto done;
523 	}
524 
525 	/*
526 	 * Add the address to the list of enabled addresses.
527 	 */
528 	bcopy(addr, p->mma_addr, mip->mi_type->mt_addr_length);
529 	p->mma_ref++;
530 	*pp = p;
531 
532 done:
533 	rw_exit(&(mip->mi_data_lock));
534 	return (err);
535 }
536 
537 int
538 mac_multicst_remove(mac_handle_t mh, const uint8_t *addr)
539 {
540 	mac_impl_t		*mip = (mac_impl_t *)mh;
541 	mac_multicst_addr_t	**pp;
542 	mac_multicst_addr_t	*p;
543 	int			err;
544 
545 	ASSERT(mip->mi_multicst != NULL);
546 
547 	/*
548 	 * Find the entry in the list for the given address.
549 	 */
550 	rw_enter(&(mip->mi_data_lock), RW_WRITER);
551 	for (pp = &(mip->mi_mmap); (p = *pp) != NULL; pp = &(p->mma_nextp)) {
552 		if (bcmp(p->mma_addr, addr, mip->mi_type->mt_addr_length) ==
553 		    0) {
554 			if (--p->mma_ref == 0)
555 				break;
556 
557 			/*
558 			 * There is still a reference to this address so
559 			 * there's nothing more to do.
560 			 */
561 			err = 0;
562 			goto done;
563 		}
564 	}
565 
566 	/*
567 	 * We did not find an entry for the given address so it is not
568 	 * currently enabled.
569 	 */
570 	if (p == NULL) {
571 		err = ENOENT;
572 		goto done;
573 	}
574 	ASSERT(p->mma_ref == 0);
575 
576 	/*
577 	 * Disable the multicast address.
578 	 */
579 	if ((err = mip->mi_multicst(mip->mi_driver, B_FALSE, addr)) != 0) {
580 		p->mma_ref++;
581 		goto done;
582 	}
583 
584 	/*
585 	 * Remove it from the list.
586 	 */
587 	*pp = p->mma_nextp;
588 	kmem_free(p, sizeof (mac_multicst_addr_t));
589 
590 done:
591 	rw_exit(&(mip->mi_data_lock));
592 	return (err);
593 }
594 
595 /*
596  * mac_unicst_verify: Verifies the passed address. It fails
597  * if the passed address is a group address or has incorrect length.
598  */
599 boolean_t
600 mac_unicst_verify(mac_handle_t mh, const uint8_t *addr, uint_t len)
601 {
602 	mac_impl_t	*mip = (mac_impl_t *)mh;
603 
604 	/*
605 	 * Verify the address.
606 	 */
607 	if ((len != mip->mi_type->mt_addr_length) ||
608 	    (mip->mi_type->mt_ops.mtops_unicst_verify(addr,
609 	    mip->mi_pdata)) != 0) {
610 		return (B_FALSE);
611 	} else {
612 		return (B_TRUE);
613 	}
614 }
615 
616 int
617 mac_unicst_set(mac_handle_t mh, const uint8_t *addr)
618 {
619 	mac_impl_t	*mip = (mac_impl_t *)mh;
620 	int		err;
621 	boolean_t	notify = B_FALSE;
622 
623 	ASSERT(mip->mi_unicst != NULL);
624 
625 	/*
626 	 * Verify the address.
627 	 */
628 	if ((err = mip->mi_type->mt_ops.mtops_unicst_verify(addr,
629 	    mip->mi_pdata)) != 0) {
630 		return (err);
631 	}
632 
633 	/*
634 	 * Program the new unicast address.
635 	 */
636 	rw_enter(&(mip->mi_data_lock), RW_WRITER);
637 
638 	/*
639 	 * If address doesn't change, do nothing.
640 	 * This check is necessary otherwise it may call into mac_unicst_set
641 	 * recursively.
642 	 */
643 	if (bcmp(addr, mip->mi_addr, mip->mi_type->mt_addr_length) == 0) {
644 		err = 0;
645 		goto done;
646 	}
647 
648 	if ((err = mip->mi_unicst(mip->mi_driver, addr)) != 0)
649 		goto done;
650 
651 	/*
652 	 * Save the address and flag that we need to send a notification.
653 	 */
654 	bcopy(addr, mip->mi_addr, mip->mi_type->mt_addr_length);
655 	notify = B_TRUE;
656 
657 done:
658 	rw_exit(&(mip->mi_data_lock));
659 
660 	if (notify)
661 		i_mac_notify(mip, MAC_NOTE_UNICST);
662 
663 	return (err);
664 }
665 
666 void
667 mac_unicst_get(mac_handle_t mh, uint8_t *addr)
668 {
669 	mac_impl_t	*mip = (mac_impl_t *)mh;
670 
671 	/*
672 	 * Copy out the current unicast source address.
673 	 */
674 	rw_enter(&(mip->mi_data_lock), RW_READER);
675 	bcopy(mip->mi_addr, addr, mip->mi_type->mt_addr_length);
676 	rw_exit(&(mip->mi_data_lock));
677 }
678 
679 void
680 mac_dest_get(mac_handle_t mh, uint8_t *addr)
681 {
682 	mac_impl_t	*mip = (mac_impl_t *)mh;
683 
684 	/*
685 	 * Copy out the current destination address.
686 	 */
687 	rw_enter(&(mip->mi_data_lock), RW_READER);
688 	bcopy(mip->mi_dstaddr, addr, mip->mi_type->mt_addr_length);
689 	rw_exit(&(mip->mi_data_lock));
690 }
691 
692 int
693 mac_promisc_set(mac_handle_t mh, boolean_t on, mac_promisc_type_t ptype)
694 {
695 	mac_impl_t	*mip = (mac_impl_t *)mh;
696 	int		err = 0;
697 
698 	ASSERT(mip->mi_setpromisc != NULL);
699 	ASSERT(ptype == MAC_DEVPROMISC || ptype == MAC_PROMISC);
700 
701 	/*
702 	 * Determine whether we should enable or disable promiscuous mode.
703 	 * For details on the distinction between "device promiscuous mode"
704 	 * and "MAC promiscuous mode", see PSARC/2005/289.
705 	 */
706 	rw_enter(&(mip->mi_data_lock), RW_WRITER);
707 	if (on) {
708 		/*
709 		 * Enable promiscuous mode on the device if not yet enabled.
710 		 */
711 		if (mip->mi_devpromisc++ == 0) {
712 			err = mip->mi_setpromisc(mip->mi_driver, B_TRUE);
713 			if (err != 0) {
714 				mip->mi_devpromisc--;
715 				goto done;
716 			}
717 			i_mac_notify(mip, MAC_NOTE_DEVPROMISC);
718 		}
719 
720 		/*
721 		 * Enable promiscuous mode on the MAC if not yet enabled.
722 		 */
723 		if (ptype == MAC_PROMISC && mip->mi_promisc++ == 0)
724 			i_mac_notify(mip, MAC_NOTE_PROMISC);
725 	} else {
726 		if (mip->mi_devpromisc == 0) {
727 			err = EPROTO;
728 			goto done;
729 		}
730 
731 		/*
732 		 * Disable promiscuous mode on the device if this is the last
733 		 * enabling.
734 		 */
735 		if (--mip->mi_devpromisc == 0) {
736 			err = mip->mi_setpromisc(mip->mi_driver, B_FALSE);
737 			if (err != 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 
778 	/*
779 	 * If the driver supports resource registration, call the driver to
780 	 * ask it to register its resources.
781 	 */
782 	if (mip->mi_callbacks->mc_callbacks & MC_RESOURCES)
783 		mip->mi_resources(mip->mi_driver);
784 }
785 
786 void
787 mac_ioctl(mac_handle_t mh, queue_t *wq, mblk_t *bp)
788 {
789 	mac_impl_t	*mip = (mac_impl_t *)mh;
790 
791 	/*
792 	 * Call the driver to handle the ioctl.  The driver may not support
793 	 * any ioctls, in which case we reply with a NAK on its behalf.
794 	 */
795 	if (mip->mi_callbacks->mc_callbacks & MC_IOCTL)
796 		mip->mi_ioctl(mip->mi_driver, wq, bp);
797 	else
798 		miocnak(wq, bp, 0, EINVAL);
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 	rw_exit(&mip->mi_txloop_lock);
828 	return (mtp);
829 }
830 
831 link_state_t
832 mac_link_get(mac_handle_t mh)
833 {
834 	return (((mac_impl_t *)mh)->mi_linkstate);
835 }
836 
837 mac_notify_handle_t
838 mac_notify_add(mac_handle_t mh, mac_notify_t notify, void *arg)
839 {
840 	mac_impl_t		*mip = (mac_impl_t *)mh;
841 	mac_notify_fn_t		*mnfp;
842 
843 	mnfp = kmem_zalloc(sizeof (mac_notify_fn_t), KM_SLEEP);
844 	mnfp->mnf_fn = notify;
845 	mnfp->mnf_arg = arg;
846 
847 	/*
848 	 * Add it to the head of the 'notify' callback list.
849 	 */
850 	rw_enter(&mip->mi_notify_lock, RW_WRITER);
851 	mnfp->mnf_nextp = mip->mi_mnfp;
852 	mip->mi_mnfp = mnfp;
853 	rw_exit(&mip->mi_notify_lock);
854 
855 	return ((mac_notify_handle_t)mnfp);
856 }
857 
858 void
859 mac_notify_remove(mac_handle_t mh, mac_notify_handle_t mnh)
860 {
861 	mac_impl_t		*mip = (mac_impl_t *)mh;
862 	mac_notify_fn_t		*mnfp = (mac_notify_fn_t *)mnh;
863 	mac_notify_fn_t		**pp;
864 	mac_notify_fn_t		*p;
865 
866 	/*
867 	 * Search the 'notify' callback list for the function closure.
868 	 */
869 	rw_enter(&mip->mi_notify_lock, RW_WRITER);
870 	for (pp = &(mip->mi_mnfp); (p = *pp) != NULL;
871 	    pp = &(p->mnf_nextp)) {
872 		if (p == mnfp)
873 			break;
874 	}
875 	ASSERT(p != NULL);
876 
877 	/*
878 	 * Remove it from the list.
879 	 */
880 	*pp = p->mnf_nextp;
881 	rw_exit(&mip->mi_notify_lock);
882 
883 	/*
884 	 * Free it.
885 	 */
886 	kmem_free(mnfp, sizeof (mac_notify_fn_t));
887 }
888 
889 void
890 mac_notify(mac_handle_t mh)
891 {
892 	mac_impl_t		*mip = (mac_impl_t *)mh;
893 	mac_notify_type_t	type;
894 
895 	for (type = 0; type < MAC_NNOTE; type++)
896 		i_mac_notify(mip, type);
897 }
898 
899 mac_rx_handle_t
900 mac_rx_add(mac_handle_t mh, mac_rx_t rx, void *arg)
901 {
902 	mac_impl_t	*mip = (mac_impl_t *)mh;
903 	mac_rx_fn_t	*mrfp;
904 
905 	mrfp = kmem_zalloc(sizeof (mac_rx_fn_t), KM_SLEEP);
906 	mrfp->mrf_fn = rx;
907 	mrfp->mrf_arg = arg;
908 
909 	/*
910 	 * Add it to the head of the 'rx' callback list.
911 	 */
912 	rw_enter(&(mip->mi_rx_lock), RW_WRITER);
913 	mrfp->mrf_nextp = mip->mi_mrfp;
914 	mip->mi_mrfp = mrfp;
915 	rw_exit(&(mip->mi_rx_lock));
916 
917 	return ((mac_rx_handle_t)mrfp);
918 }
919 
920 /*
921  * Unregister a receive function for this mac.  This removes the function
922  * from the list of receive functions for this mac.
923  */
924 void
925 mac_rx_remove(mac_handle_t mh, mac_rx_handle_t mrh)
926 {
927 	mac_impl_t		*mip = (mac_impl_t *)mh;
928 	mac_rx_fn_t		*mrfp = (mac_rx_fn_t *)mrh;
929 	mac_rx_fn_t		**pp;
930 	mac_rx_fn_t		*p;
931 
932 	/*
933 	 * Search the 'rx' callback list for the function closure.
934 	 */
935 	rw_enter(&(mip->mi_rx_lock), RW_WRITER);
936 	for (pp = &(mip->mi_mrfp); (p = *pp) != NULL; pp = &(p->mrf_nextp)) {
937 		if (p == mrfp)
938 			break;
939 	}
940 	ASSERT(p != NULL);
941 
942 	/* Remove it from the list. */
943 	*pp = p->mrf_nextp;
944 	kmem_free(mrfp, sizeof (mac_rx_fn_t));
945 	rw_exit(&(mip->mi_rx_lock));
946 }
947 
948 mac_txloop_handle_t
949 mac_txloop_add(mac_handle_t mh, mac_txloop_t tx, void *arg)
950 {
951 	mac_impl_t	*mip = (mac_impl_t *)mh;
952 	mac_txloop_fn_t	*mtfp;
953 
954 	mtfp = kmem_zalloc(sizeof (mac_txloop_fn_t), KM_SLEEP);
955 	mtfp->mtf_fn = tx;
956 	mtfp->mtf_arg = arg;
957 
958 	/*
959 	 * Add it to the head of the 'tx' callback list.
960 	 */
961 	rw_enter(&(mip->mi_txloop_lock), RW_WRITER);
962 	mtfp->mtf_nextp = mip->mi_mtfp;
963 	mip->mi_mtfp = mtfp;
964 	rw_exit(&(mip->mi_txloop_lock));
965 
966 	return ((mac_txloop_handle_t)mtfp);
967 }
968 
969 /*
970  * Unregister a transmit function for this mac.  This removes the function
971  * from the list of transmit functions for this mac.
972  */
973 void
974 mac_txloop_remove(mac_handle_t mh, mac_txloop_handle_t mth)
975 {
976 	mac_impl_t		*mip = (mac_impl_t *)mh;
977 	mac_txloop_fn_t		*mtfp = (mac_txloop_fn_t *)mth;
978 	mac_txloop_fn_t		**pp;
979 	mac_txloop_fn_t		*p;
980 
981 	/*
982 	 * Search the 'tx' callback list for the function.
983 	 */
984 	rw_enter(&(mip->mi_txloop_lock), RW_WRITER);
985 	for (pp = &(mip->mi_mtfp); (p = *pp) != NULL; pp = &(p->mtf_nextp)) {
986 		if (p == mtfp)
987 			break;
988 	}
989 	ASSERT(p != NULL);
990 
991 	/* Remove it from the list. */
992 	*pp = p->mtf_nextp;
993 	kmem_free(mtfp, sizeof (mac_txloop_fn_t));
994 	rw_exit(&(mip->mi_txloop_lock));
995 }
996 
997 void
998 mac_resource_set(mac_handle_t mh, mac_resource_add_t add, void *arg)
999 {
1000 	mac_impl_t		*mip = (mac_impl_t *)mh;
1001 
1002 	/*
1003 	 * Update the 'resource_add' callbacks.
1004 	 */
1005 	rw_enter(&(mip->mi_resource_lock), RW_WRITER);
1006 	mip->mi_resource_add = add;
1007 	mip->mi_resource_add_arg = arg;
1008 	rw_exit(&(mip->mi_resource_lock));
1009 }
1010 
1011 /*
1012  * Driver support functions.
1013  */
1014 
1015 mac_register_t *
1016 mac_alloc(uint_t mac_version)
1017 {
1018 	mac_register_t *mregp;
1019 
1020 	/*
1021 	 * Make sure there isn't a version mismatch between the driver and
1022 	 * the framework.  In the future, if multiple versions are
1023 	 * supported, this check could become more sophisticated.
1024 	 */
1025 	if (mac_version != MAC_VERSION)
1026 		return (NULL);
1027 
1028 	mregp = kmem_zalloc(sizeof (mac_register_t), KM_SLEEP);
1029 	mregp->m_version = mac_version;
1030 	return (mregp);
1031 }
1032 
1033 void
1034 mac_free(mac_register_t *mregp)
1035 {
1036 	kmem_free(mregp, sizeof (mac_register_t));
1037 }
1038 
1039 /*
1040  * mac_register() is how drivers register new MACs with the GLDv3
1041  * framework.  The mregp argument is allocated by drivers using the
1042  * mac_alloc() function, and can be freed using mac_free() immediately upon
1043  * return from mac_register().  Upon success (0 return value), the mhp
1044  * opaque pointer becomes the driver's handle to its MAC interface, and is
1045  * the argument to all other mac module entry points.
1046  */
1047 int
1048 mac_register(mac_register_t *mregp, mac_handle_t *mhp)
1049 {
1050 	mac_impl_t	*mip;
1051 	mactype_t	*mtype;
1052 	int		err;
1053 	struct devnames *dnp;
1054 	minor_t		minor;
1055 	mod_hash_val_t	val;
1056 	boolean_t	style1_created = B_FALSE, style2_created = B_FALSE;
1057 
1058 	/* Find the required MAC-Type plugin. */
1059 	if ((mtype = i_mactype_getplugin(mregp->m_type_ident)) == NULL)
1060 		return (EINVAL);
1061 
1062 	/* Create a mac_impl_t to represent this MAC. */
1063 	mip = kmem_cache_alloc(i_mac_impl_cachep, KM_SLEEP);
1064 
1065 	/*
1066 	 * The mac is not ready for open yet.
1067 	 */
1068 	mip->mi_disabled = B_TRUE;
1069 
1070 	mip->mi_drvname = ddi_driver_name(mregp->m_dip);
1071 	/*
1072 	 * Some drivers such as aggr need to register multiple MACs.  Such
1073 	 * drivers must supply a non-zero "instance" argument so that each
1074 	 * MAC can be assigned a unique MAC name and can have unique
1075 	 * kstats.
1076 	 */
1077 	mip->mi_instance = ((mregp->m_instance == 0) ?
1078 	    ddi_get_instance(mregp->m_dip) : mregp->m_instance);
1079 
1080 	/* Construct the MAC name as <drvname><instance> */
1081 	(void) snprintf(mip->mi_name, sizeof (mip->mi_name), "%s%d",
1082 	    mip->mi_drvname, mip->mi_instance);
1083 
1084 	rw_enter(&i_mac_impl_lock, RW_WRITER);
1085 	if (mod_hash_insert(i_mac_impl_hash,
1086 	    (mod_hash_key_t)mip->mi_name, (mod_hash_val_t)mip) != 0) {
1087 		kmem_cache_free(i_mac_impl_cachep, mip);
1088 		rw_exit(&i_mac_impl_lock);
1089 		return (EEXIST);
1090 	}
1091 	atomic_inc_32(&i_mac_impl_count);
1092 
1093 	mip->mi_driver = mregp->m_driver;
1094 
1095 	mip->mi_type = mtype;
1096 	mip->mi_info.mi_media = mtype->mt_type;
1097 	mip->mi_info.mi_nativemedia = mtype->mt_nativetype;
1098 	mip->mi_info.mi_sdu_min = mregp->m_min_sdu;
1099 	if (mregp->m_max_sdu <= mregp->m_min_sdu) {
1100 		err = EINVAL;
1101 		goto fail;
1102 	}
1103 	mip->mi_info.mi_sdu_max = mregp->m_max_sdu;
1104 	mip->mi_info.mi_addr_length = mip->mi_type->mt_addr_length;
1105 	/*
1106 	 * If the media supports a broadcast address, cache a pointer to it
1107 	 * in the mac_info_t so that upper layers can use it.
1108 	 */
1109 	mip->mi_info.mi_brdcst_addr = mip->mi_type->mt_brdcst_addr;
1110 
1111 	/*
1112 	 * Copy the unicast source address into the mac_info_t, but only if
1113 	 * the MAC-Type defines a non-zero address length.  We need to
1114 	 * handle MAC-Types that have an address length of 0
1115 	 * (point-to-point protocol MACs for example).
1116 	 */
1117 	if (mip->mi_type->mt_addr_length > 0) {
1118 		if (mregp->m_src_addr == NULL) {
1119 			err = EINVAL;
1120 			goto fail;
1121 		}
1122 		mip->mi_info.mi_unicst_addr =
1123 		    kmem_alloc(mip->mi_type->mt_addr_length, KM_SLEEP);
1124 		bcopy(mregp->m_src_addr, mip->mi_info.mi_unicst_addr,
1125 		    mip->mi_type->mt_addr_length);
1126 
1127 		/*
1128 		 * Copy the fixed 'factory' MAC address from the immutable
1129 		 * info.  This is taken to be the MAC address currently in
1130 		 * use.
1131 		 */
1132 		bcopy(mip->mi_info.mi_unicst_addr, mip->mi_addr,
1133 		    mip->mi_type->mt_addr_length);
1134 		/* Copy the destination address if one is provided. */
1135 		if (mregp->m_dst_addr != NULL) {
1136 			bcopy(mregp->m_dst_addr, mip->mi_dstaddr,
1137 			    mip->mi_type->mt_addr_length);
1138 		}
1139 	} else if (mregp->m_src_addr != NULL) {
1140 		err = EINVAL;
1141 		goto fail;
1142 	}
1143 
1144 	/*
1145 	 * The format of the m_pdata is specific to the plugin.  It is
1146 	 * passed in as an argument to all of the plugin callbacks.  The
1147 	 * driver can update this information by calling
1148 	 * mac_pdata_update().
1149 	 */
1150 	if (mregp->m_pdata != NULL) {
1151 		/*
1152 		 * Verify that the plugin supports MAC plugin data and that
1153 		 * the supplied data is valid.
1154 		 */
1155 		if (!(mip->mi_type->mt_ops.mtops_ops & MTOPS_PDATA_VERIFY)) {
1156 			err = EINVAL;
1157 			goto fail;
1158 		}
1159 		if (!mip->mi_type->mt_ops.mtops_pdata_verify(mregp->m_pdata,
1160 		    mregp->m_pdata_size)) {
1161 			err = EINVAL;
1162 			goto fail;
1163 		}
1164 		mip->mi_pdata = kmem_alloc(mregp->m_pdata_size, KM_SLEEP);
1165 		bcopy(mregp->m_pdata, mip->mi_pdata, mregp->m_pdata_size);
1166 		mip->mi_pdata_size = mregp->m_pdata_size;
1167 	}
1168 
1169 	/*
1170 	 * Stash the driver callbacks into the mac_impl_t, but first sanity
1171 	 * check to make sure all mandatory callbacks are set.
1172 	 */
1173 	if (mregp->m_callbacks->mc_getstat == NULL ||
1174 	    mregp->m_callbacks->mc_start == NULL ||
1175 	    mregp->m_callbacks->mc_stop == NULL ||
1176 	    mregp->m_callbacks->mc_setpromisc == NULL ||
1177 	    mregp->m_callbacks->mc_multicst == NULL ||
1178 	    mregp->m_callbacks->mc_unicst == NULL ||
1179 	    mregp->m_callbacks->mc_tx == NULL) {
1180 		err = EINVAL;
1181 		goto fail;
1182 	}
1183 	mip->mi_callbacks = mregp->m_callbacks;
1184 
1185 	mip->mi_dip = mregp->m_dip;
1186 
1187 	/*
1188 	 * Set up the two possible transmit routines.
1189 	 */
1190 	mip->mi_txinfo.mt_fn = mip->mi_tx;
1191 	mip->mi_txinfo.mt_arg = mip->mi_driver;
1192 	mip->mi_txloopinfo.mt_fn = mac_txloop;
1193 	mip->mi_txloopinfo.mt_arg = mip;
1194 
1195 	/*
1196 	 * Initialize the kstats for this device.
1197 	 */
1198 	mac_stat_create(mip);
1199 
1200 	err = EEXIST;
1201 	/* Create a style-2 DLPI device */
1202 	if (ddi_create_minor_node(mip->mi_dip, (char *)mip->mi_drvname,
1203 	    S_IFCHR, 0, DDI_NT_NET, CLONE_DEV) != DDI_SUCCESS)
1204 		goto fail;
1205 	style2_created = B_TRUE;
1206 
1207 	/* Create a style-1 DLPI device */
1208 	minor = (minor_t)mip->mi_instance + 1;
1209 	if (ddi_create_minor_node(mip->mi_dip, mip->mi_name, S_IFCHR, minor,
1210 	    DDI_NT_NET, 0) != DDI_SUCCESS)
1211 		goto fail;
1212 	style1_created = B_TRUE;
1213 
1214 	/*
1215 	 * Create a link for this MAC.  The link name will be the same as
1216 	 * the MAC name.
1217 	 */
1218 	err = dls_create(mip->mi_name, mip->mi_name,
1219 	    ddi_get_instance(mip->mi_dip));
1220 	if (err != 0)
1221 		goto fail;
1222 
1223 	/* set the gldv3 flag in dn_flags */
1224 	dnp = &devnamesp[ddi_driver_major(mip->mi_dip)];
1225 	LOCK_DEV_OPS(&dnp->dn_lock);
1226 	dnp->dn_flags |= DN_GLDV3_DRIVER;
1227 	UNLOCK_DEV_OPS(&dnp->dn_lock);
1228 
1229 	/*
1230 	 * Mark the MAC to be ready for open.
1231 	 */
1232 	mip->mi_disabled = B_FALSE;
1233 
1234 	cmn_err(CE_NOTE, "!%s registered", mip->mi_name);
1235 	rw_exit(&i_mac_impl_lock);
1236 	*mhp = (mac_handle_t)mip;
1237 	return (0);
1238 
1239 fail:
1240 	(void) mod_hash_remove(i_mac_impl_hash, (mod_hash_key_t)mip->mi_name,
1241 	    &val);
1242 	ASSERT(mip == (mac_impl_t *)val);
1243 	atomic_dec_32(&i_mac_impl_count);
1244 
1245 	if (mip->mi_info.mi_unicst_addr != NULL) {
1246 		kmem_free(mip->mi_info.mi_unicst_addr,
1247 		    mip->mi_type->mt_addr_length);
1248 		mip->mi_info.mi_unicst_addr = NULL;
1249 	}
1250 	if (style1_created)
1251 		ddi_remove_minor_node(mip->mi_dip, mip->mi_name);
1252 	if (style2_created)
1253 		ddi_remove_minor_node(mip->mi_dip, (char *)mip->mi_drvname);
1254 
1255 	mac_stat_destroy(mip);
1256 
1257 	if (mip->mi_type != NULL) {
1258 		atomic_dec_32(&mip->mi_type->mt_ref);
1259 		mip->mi_type = NULL;
1260 	}
1261 
1262 	if (mip->mi_pdata != NULL) {
1263 		kmem_free(mip->mi_pdata, mip->mi_pdata_size);
1264 		mip->mi_pdata = NULL;
1265 		mip->mi_pdata_size = 0;
1266 	}
1267 
1268 	kmem_cache_free(i_mac_impl_cachep, mip);
1269 	rw_exit(&i_mac_impl_lock);
1270 	return (err);
1271 }
1272 
1273 int
1274 mac_unregister(mac_handle_t mh)
1275 {
1276 	int			err;
1277 	mac_impl_t		*mip = (mac_impl_t *)mh;
1278 	mod_hash_val_t		val;
1279 	mac_multicst_addr_t	*p, *nextp;
1280 
1281 	/*
1282 	 * See if there are any other references to this mac_t (e.g., VLAN's).
1283 	 * If not, set mi_disabled to prevent any new VLAN's from being
1284 	 * created while we're destroying this mac.
1285 	 */
1286 	rw_enter(&i_mac_impl_lock, RW_WRITER);
1287 	if (mip->mi_ref > 0) {
1288 		rw_exit(&i_mac_impl_lock);
1289 		return (EBUSY);
1290 	}
1291 	mip->mi_disabled = B_TRUE;
1292 	rw_exit(&i_mac_impl_lock);
1293 
1294 	/*
1295 	 * Wait for all taskqs which process the mac notifications to finish.
1296 	 */
1297 	mutex_enter(&mip->mi_notify_ref_lock);
1298 	while (mip->mi_notify_ref != 0)
1299 		cv_wait(&mip->mi_notify_cv, &mip->mi_notify_ref_lock);
1300 	mutex_exit(&mip->mi_notify_ref_lock);
1301 
1302 	if ((err = dls_destroy(mip->mi_name)) != 0) {
1303 		rw_enter(&i_mac_impl_lock, RW_WRITER);
1304 		mip->mi_disabled = B_FALSE;
1305 		rw_exit(&i_mac_impl_lock);
1306 		return (err);
1307 	}
1308 
1309 	/*
1310 	 * Remove both style 1 and style 2 minor nodes
1311 	 */
1312 	ddi_remove_minor_node(mip->mi_dip, (char *)mip->mi_drvname);
1313 	ddi_remove_minor_node(mip->mi_dip, mip->mi_name);
1314 
1315 	ASSERT(!mip->mi_activelink);
1316 
1317 	mac_stat_destroy(mip);
1318 
1319 	(void) mod_hash_remove(i_mac_impl_hash, (mod_hash_key_t)mip->mi_name,
1320 	    &val);
1321 	ASSERT(mip == (mac_impl_t *)val);
1322 
1323 	ASSERT(i_mac_impl_count > 0);
1324 	atomic_dec_32(&i_mac_impl_count);
1325 
1326 	if (mip->mi_pdata != NULL)
1327 		kmem_free(mip->mi_pdata, mip->mi_pdata_size);
1328 	mip->mi_pdata = NULL;
1329 	mip->mi_pdata_size = 0;
1330 
1331 	/*
1332 	 * Free the list of multicast addresses.
1333 	 */
1334 	for (p = mip->mi_mmap; p != NULL; p = nextp) {
1335 		nextp = p->mma_nextp;
1336 		kmem_free(p, sizeof (mac_multicst_addr_t));
1337 	}
1338 	mip->mi_mmap = NULL;
1339 
1340 	mip->mi_linkstate = LINK_STATE_UNKNOWN;
1341 	kmem_free(mip->mi_info.mi_unicst_addr, mip->mi_type->mt_addr_length);
1342 	mip->mi_info.mi_unicst_addr = NULL;
1343 
1344 	atomic_dec_32(&mip->mi_type->mt_ref);
1345 	mip->mi_type = NULL;
1346 
1347 	cmn_err(CE_NOTE, "!%s unregistered", mip->mi_name);
1348 
1349 	kmem_cache_free(i_mac_impl_cachep, mip);
1350 
1351 	return (0);
1352 }
1353 
1354 void
1355 mac_rx(mac_handle_t mh, mac_resource_handle_t mrh, mblk_t *bp)
1356 {
1357 	mac_impl_t	*mip = (mac_impl_t *)mh;
1358 	mac_rx_fn_t	*mrfp;
1359 
1360 	/*
1361 	 * Call all registered receive functions.
1362 	 */
1363 	rw_enter(&mip->mi_rx_lock, RW_READER);
1364 	mrfp = mip->mi_mrfp;
1365 	if (mrfp == NULL) {
1366 		/* There are no registered receive functions. */
1367 		freemsgchain(bp);
1368 		rw_exit(&mip->mi_rx_lock);
1369 		return;
1370 	}
1371 	do {
1372 		mblk_t *recv_bp;
1373 
1374 		if (mrfp->mrf_nextp != NULL) {
1375 			/* XXX Do we bump a counter if copymsgchain() fails? */
1376 			recv_bp = copymsgchain(bp);
1377 		} else {
1378 			recv_bp = bp;
1379 		}
1380 		if (recv_bp != NULL)
1381 			mrfp->mrf_fn(mrfp->mrf_arg, mrh, recv_bp);
1382 		mrfp = mrfp->mrf_nextp;
1383 	} while (mrfp != NULL);
1384 	rw_exit(&mip->mi_rx_lock);
1385 }
1386 
1387 /*
1388  * Transmit function -- ONLY used when there are registered loopback listeners.
1389  */
1390 mblk_t *
1391 mac_txloop(void *arg, mblk_t *bp)
1392 {
1393 	mac_impl_t	*mip = arg;
1394 	mac_txloop_fn_t	*mtfp;
1395 	mblk_t		*loop_bp, *resid_bp, *next_bp;
1396 
1397 	while (bp != NULL) {
1398 		next_bp = bp->b_next;
1399 		bp->b_next = NULL;
1400 
1401 		if ((loop_bp = copymsg(bp)) == NULL)
1402 			goto noresources;
1403 
1404 		if ((resid_bp = mip->mi_tx(mip->mi_driver, bp)) != NULL) {
1405 			ASSERT(resid_bp == bp);
1406 			freemsg(loop_bp);
1407 			goto noresources;
1408 		}
1409 
1410 		rw_enter(&mip->mi_txloop_lock, RW_READER);
1411 		mtfp = mip->mi_mtfp;
1412 		while (mtfp != NULL && loop_bp != NULL) {
1413 			bp = loop_bp;
1414 
1415 			/* XXX counter bump if copymsg() fails? */
1416 			if (mtfp->mtf_nextp != NULL)
1417 				loop_bp = copymsg(bp);
1418 			else
1419 				loop_bp = NULL;
1420 
1421 			mtfp->mtf_fn(mtfp->mtf_arg, bp);
1422 			mtfp = mtfp->mtf_nextp;
1423 		}
1424 		rw_exit(&mip->mi_txloop_lock);
1425 
1426 		/*
1427 		 * It's possible we've raced with the disabling of promiscuous
1428 		 * mode, in which case we can discard our copy.
1429 		 */
1430 		if (loop_bp != NULL)
1431 			freemsg(loop_bp);
1432 
1433 		bp = next_bp;
1434 	}
1435 
1436 	return (NULL);
1437 
1438 noresources:
1439 	bp->b_next = next_bp;
1440 	return (bp);
1441 }
1442 
1443 void
1444 mac_link_update(mac_handle_t mh, link_state_t link)
1445 {
1446 	mac_impl_t	*mip = (mac_impl_t *)mh;
1447 
1448 	/*
1449 	 * Save the link state.
1450 	 */
1451 	mip->mi_linkstate = link;
1452 
1453 	/*
1454 	 * Send a MAC_NOTE_LINK notification.
1455 	 */
1456 	i_mac_notify(mip, MAC_NOTE_LINK);
1457 }
1458 
1459 void
1460 mac_unicst_update(mac_handle_t mh, const uint8_t *addr)
1461 {
1462 	mac_impl_t	*mip = (mac_impl_t *)mh;
1463 
1464 	if (mip->mi_type->mt_addr_length == 0)
1465 		return;
1466 
1467 	/*
1468 	 * Save the address.
1469 	 */
1470 	bcopy(addr, mip->mi_addr, mip->mi_type->mt_addr_length);
1471 
1472 	/*
1473 	 * Send a MAC_NOTE_UNICST notification.
1474 	 */
1475 	i_mac_notify(mip, MAC_NOTE_UNICST);
1476 }
1477 
1478 void
1479 mac_tx_update(mac_handle_t mh)
1480 {
1481 	/*
1482 	 * Send a MAC_NOTE_TX notification.
1483 	 */
1484 	i_mac_notify((mac_impl_t *)mh, MAC_NOTE_TX);
1485 }
1486 
1487 void
1488 mac_resource_update(mac_handle_t mh)
1489 {
1490 	/*
1491 	 * Send a MAC_NOTE_RESOURCE notification.
1492 	 */
1493 	i_mac_notify((mac_impl_t *)mh, MAC_NOTE_RESOURCE);
1494 }
1495 
1496 mac_resource_handle_t
1497 mac_resource_add(mac_handle_t mh, mac_resource_t *mrp)
1498 {
1499 	mac_impl_t		*mip = (mac_impl_t *)mh;
1500 	mac_resource_handle_t	mrh;
1501 	mac_resource_add_t	add;
1502 	void			*arg;
1503 
1504 	rw_enter(&mip->mi_resource_lock, RW_READER);
1505 	add = mip->mi_resource_add;
1506 	arg = mip->mi_resource_add_arg;
1507 
1508 	if (add != NULL)
1509 		mrh = add(arg, mrp);
1510 	else
1511 		mrh = NULL;
1512 	rw_exit(&mip->mi_resource_lock);
1513 
1514 	return (mrh);
1515 }
1516 
1517 int
1518 mac_pdata_update(mac_handle_t mh, void *mac_pdata, size_t dsize)
1519 {
1520 	mac_impl_t	*mip = (mac_impl_t *)mh;
1521 
1522 	/*
1523 	 * Verify that the plugin supports MAC plugin data and that the
1524 	 * supplied data is valid.
1525 	 */
1526 	if (!(mip->mi_type->mt_ops.mtops_ops & MTOPS_PDATA_VERIFY))
1527 		return (EINVAL);
1528 	if (!mip->mi_type->mt_ops.mtops_pdata_verify(mac_pdata, dsize))
1529 		return (EINVAL);
1530 
1531 	if (mip->mi_pdata != NULL)
1532 		kmem_free(mip->mi_pdata, mip->mi_pdata_size);
1533 
1534 	mip->mi_pdata = kmem_alloc(dsize, KM_SLEEP);
1535 	bcopy(mac_pdata, mip->mi_pdata, dsize);
1536 	mip->mi_pdata_size = dsize;
1537 
1538 	/*
1539 	 * Since the MAC plugin data is used to construct MAC headers that
1540 	 * were cached in fast-path headers, we need to flush fast-path
1541 	 * information for links associated with this mac.
1542 	 */
1543 	i_mac_notify(mip, MAC_NOTE_FASTPATH_FLUSH);
1544 	return (0);
1545 }
1546 
1547 void
1548 mac_multicst_refresh(mac_handle_t mh, mac_multicst_t refresh, void *arg,
1549     boolean_t add)
1550 {
1551 	mac_impl_t		*mip = (mac_impl_t *)mh;
1552 	mac_multicst_addr_t	*p;
1553 
1554 	/*
1555 	 * If no specific refresh function was given then default to the
1556 	 * driver's m_multicst entry point.
1557 	 */
1558 	if (refresh == NULL) {
1559 		refresh = mip->mi_multicst;
1560 		arg = mip->mi_driver;
1561 	}
1562 	ASSERT(refresh != NULL);
1563 
1564 	/*
1565 	 * Walk the multicast address list and call the refresh function for
1566 	 * each address.
1567 	 */
1568 	rw_enter(&(mip->mi_data_lock), RW_READER);
1569 	for (p = mip->mi_mmap; p != NULL; p = p->mma_nextp)
1570 		refresh(arg, add, p->mma_addr);
1571 	rw_exit(&(mip->mi_data_lock));
1572 }
1573 
1574 void
1575 mac_unicst_refresh(mac_handle_t mh, mac_unicst_t refresh, void *arg)
1576 {
1577 	mac_impl_t	*mip = (mac_impl_t *)mh;
1578 	/*
1579 	 * If no specific refresh function was given then default to the
1580 	 * driver's mi_unicst entry point.
1581 	 */
1582 	if (refresh == NULL) {
1583 		refresh = mip->mi_unicst;
1584 		arg = mip->mi_driver;
1585 	}
1586 	ASSERT(refresh != NULL);
1587 
1588 	/*
1589 	 * Call the refresh function with the current unicast address.
1590 	 */
1591 	refresh(arg, mip->mi_addr);
1592 }
1593 
1594 void
1595 mac_promisc_refresh(mac_handle_t mh, mac_setpromisc_t refresh, void *arg)
1596 {
1597 	mac_impl_t	*mip = (mac_impl_t *)mh;
1598 
1599 	/*
1600 	 * If no specific refresh function was given then default to the
1601 	 * driver's m_promisc entry point.
1602 	 */
1603 	if (refresh == NULL) {
1604 		refresh = mip->mi_setpromisc;
1605 		arg = mip->mi_driver;
1606 	}
1607 	ASSERT(refresh != NULL);
1608 
1609 	/*
1610 	 * Call the refresh function with the current promiscuity.
1611 	 */
1612 	refresh(arg, (mip->mi_devpromisc != 0));
1613 }
1614 
1615 boolean_t
1616 mac_active_set(mac_handle_t mh)
1617 {
1618 	mac_impl_t *mip = (mac_impl_t *)mh;
1619 
1620 	mutex_enter(&mip->mi_activelink_lock);
1621 	if (mip->mi_activelink) {
1622 		mutex_exit(&mip->mi_activelink_lock);
1623 		return (B_FALSE);
1624 	}
1625 	mip->mi_activelink = B_TRUE;
1626 	mutex_exit(&mip->mi_activelink_lock);
1627 	return (B_TRUE);
1628 }
1629 
1630 void
1631 mac_active_clear(mac_handle_t mh)
1632 {
1633 	mac_impl_t *mip = (mac_impl_t *)mh;
1634 
1635 	mutex_enter(&mip->mi_activelink_lock);
1636 	ASSERT(mip->mi_activelink);
1637 	mip->mi_activelink = B_FALSE;
1638 	mutex_exit(&mip->mi_activelink_lock);
1639 }
1640 
1641 /*
1642  * mac_info_get() is used for retrieving the mac_info when a DL_INFO_REQ is
1643  * issued before a DL_ATTACH_REQ. we walk the i_mac_impl_hash table and find
1644  * the first mac_impl_t with a matching driver name; then we copy its mac_info_t
1645  * to the caller. we do all this with i_mac_impl_lock held so the mac_impl_t
1646  * cannot disappear while we are accessing it.
1647  */
1648 typedef struct i_mac_info_state_s {
1649 	const char	*mi_name;
1650 	mac_info_t	*mi_infop;
1651 } i_mac_info_state_t;
1652 
1653 /*ARGSUSED*/
1654 static uint_t
1655 i_mac_info_walker(mod_hash_key_t key, mod_hash_val_t *val, void *arg)
1656 {
1657 	i_mac_info_state_t	*statep = arg;
1658 	mac_impl_t		*mip = (mac_impl_t *)val;
1659 
1660 	if (mip->mi_disabled)
1661 		return (MH_WALK_CONTINUE);
1662 
1663 	if (strcmp(statep->mi_name,
1664 	    ddi_driver_name(mip->mi_dip)) != 0)
1665 		return (MH_WALK_CONTINUE);
1666 
1667 	statep->mi_infop = &mip->mi_info;
1668 	return (MH_WALK_TERMINATE);
1669 }
1670 
1671 boolean_t
1672 mac_info_get(const char *name, mac_info_t *minfop)
1673 {
1674 	i_mac_info_state_t	state;
1675 
1676 	rw_enter(&i_mac_impl_lock, RW_READER);
1677 	state.mi_name = name;
1678 	state.mi_infop = NULL;
1679 	mod_hash_walk(i_mac_impl_hash, i_mac_info_walker, &state);
1680 	if (state.mi_infop == NULL) {
1681 		rw_exit(&i_mac_impl_lock);
1682 		return (B_FALSE);
1683 	}
1684 	*minfop = *state.mi_infop;
1685 	rw_exit(&i_mac_impl_lock);
1686 	return (B_TRUE);
1687 }
1688 
1689 boolean_t
1690 mac_capab_get(mac_handle_t mh, mac_capab_t cap, void *cap_data)
1691 {
1692 	mac_impl_t *mip = (mac_impl_t *)mh;
1693 
1694 	if (mip->mi_callbacks->mc_callbacks & MC_GETCAPAB)
1695 		return (mip->mi_getcapab(mip->mi_driver, cap, cap_data));
1696 	else
1697 		return (B_FALSE);
1698 }
1699 
1700 boolean_t
1701 mac_sap_verify(mac_handle_t mh, uint32_t sap, uint32_t *bind_sap)
1702 {
1703 	mac_impl_t	*mip = (mac_impl_t *)mh;
1704 	return (mip->mi_type->mt_ops.mtops_sap_verify(sap, bind_sap,
1705 	    mip->mi_pdata));
1706 }
1707 
1708 mblk_t *
1709 mac_header(mac_handle_t mh, const uint8_t *daddr, uint32_t sap, mblk_t *payload,
1710     size_t extra_len)
1711 {
1712 	mac_impl_t	*mip = (mac_impl_t *)mh;
1713 	return (mip->mi_type->mt_ops.mtops_header(mip->mi_addr, daddr, sap,
1714 	    mip->mi_pdata, payload, extra_len));
1715 }
1716 
1717 int
1718 mac_header_info(mac_handle_t mh, mblk_t *mp, mac_header_info_t *mhip)
1719 {
1720 	mac_impl_t	*mip = (mac_impl_t *)mh;
1721 	return (mip->mi_type->mt_ops.mtops_header_info(mp, mip->mi_pdata,
1722 	    mhip));
1723 }
1724 
1725 mblk_t *
1726 mac_header_cook(mac_handle_t mh, mblk_t *mp)
1727 {
1728 	mac_impl_t	*mip = (mac_impl_t *)mh;
1729 	if (mip->mi_type->mt_ops.mtops_ops & MTOPS_HEADER_COOK) {
1730 		if (DB_REF(mp) > 1) {
1731 			mblk_t *newmp = copymsg(mp);
1732 			if (newmp == NULL)
1733 				return (NULL);
1734 			freemsg(mp);
1735 			mp = newmp;
1736 		}
1737 		return (mip->mi_type->mt_ops.mtops_header_cook(mp,
1738 		    mip->mi_pdata));
1739 	}
1740 	return (mp);
1741 }
1742 
1743 mblk_t *
1744 mac_header_uncook(mac_handle_t mh, mblk_t *mp)
1745 {
1746 	mac_impl_t	*mip = (mac_impl_t *)mh;
1747 	if (mip->mi_type->mt_ops.mtops_ops & MTOPS_HEADER_UNCOOK) {
1748 		if (DB_REF(mp) > 1) {
1749 			mblk_t *newmp = copymsg(mp);
1750 			if (newmp == NULL)
1751 				return (NULL);
1752 			freemsg(mp);
1753 			mp = newmp;
1754 		}
1755 		return (mip->mi_type->mt_ops.mtops_header_uncook(mp,
1756 		    mip->mi_pdata));
1757 	}
1758 	return (mp);
1759 }
1760 
1761 void
1762 mac_init_ops(struct dev_ops *ops, const char *name)
1763 {
1764 	dld_init_ops(ops, name);
1765 }
1766 
1767 void
1768 mac_fini_ops(struct dev_ops *ops)
1769 {
1770 	dld_fini_ops(ops);
1771 }
1772 
1773 /*
1774  * MAC Type Plugin functions.
1775  */
1776 
1777 mactype_register_t *
1778 mactype_alloc(uint_t mactype_version)
1779 {
1780 	mactype_register_t *mtrp;
1781 
1782 	/*
1783 	 * Make sure there isn't a version mismatch between the plugin and
1784 	 * the framework.  In the future, if multiple versions are
1785 	 * supported, this check could become more sophisticated.
1786 	 */
1787 	if (mactype_version != MACTYPE_VERSION)
1788 		return (NULL);
1789 
1790 	mtrp = kmem_zalloc(sizeof (mactype_register_t), KM_SLEEP);
1791 	mtrp->mtr_version = mactype_version;
1792 	return (mtrp);
1793 }
1794 
1795 void
1796 mactype_free(mactype_register_t *mtrp)
1797 {
1798 	kmem_free(mtrp, sizeof (mactype_register_t));
1799 }
1800 
1801 int
1802 mactype_register(mactype_register_t *mtrp)
1803 {
1804 	mactype_t	*mtp;
1805 	mactype_ops_t	*ops = mtrp->mtr_ops;
1806 
1807 	/* Do some sanity checking before we register this MAC type. */
1808 	if (mtrp->mtr_ident == NULL || ops == NULL || mtrp->mtr_addrlen == 0)
1809 		return (EINVAL);
1810 
1811 	/*
1812 	 * Verify that all mandatory callbacks are set in the ops
1813 	 * vector.
1814 	 */
1815 	if (ops->mtops_unicst_verify == NULL ||
1816 	    ops->mtops_multicst_verify == NULL ||
1817 	    ops->mtops_sap_verify == NULL ||
1818 	    ops->mtops_header == NULL ||
1819 	    ops->mtops_header_info == NULL) {
1820 		return (EINVAL);
1821 	}
1822 
1823 	mtp = kmem_zalloc(sizeof (*mtp), KM_SLEEP);
1824 	mtp->mt_ident = mtrp->mtr_ident;
1825 	mtp->mt_ops = *ops;
1826 	mtp->mt_type = mtrp->mtr_mactype;
1827 	mtp->mt_nativetype = mtrp->mtr_nativetype;
1828 	mtp->mt_addr_length = mtrp->mtr_addrlen;
1829 	if (mtrp->mtr_brdcst_addr != NULL) {
1830 		mtp->mt_brdcst_addr = kmem_alloc(mtrp->mtr_addrlen, KM_SLEEP);
1831 		bcopy(mtrp->mtr_brdcst_addr, mtp->mt_brdcst_addr,
1832 		    mtrp->mtr_addrlen);
1833 	}
1834 
1835 	mtp->mt_stats = mtrp->mtr_stats;
1836 	mtp->mt_statcount = mtrp->mtr_statcount;
1837 
1838 	if (mod_hash_insert(i_mactype_hash,
1839 	    (mod_hash_key_t)mtp->mt_ident, (mod_hash_val_t)mtp) != 0) {
1840 		kmem_free(mtp->mt_brdcst_addr, mtp->mt_addr_length);
1841 		kmem_free(mtp, sizeof (*mtp));
1842 		return (EEXIST);
1843 	}
1844 	return (0);
1845 }
1846 
1847 int
1848 mactype_unregister(const char *ident)
1849 {
1850 	mactype_t	*mtp;
1851 	mod_hash_val_t	val;
1852 	int 		err;
1853 
1854 	/*
1855 	 * Let's not allow MAC drivers to use this plugin while we're
1856 	 * trying to unregister it.  Holding i_mactype_lock also prevents a
1857 	 * plugin from unregistering while a MAC driver is attempting to
1858 	 * hold a reference to it in i_mactype_getplugin().
1859 	 */
1860 	mutex_enter(&i_mactype_lock);
1861 
1862 	if ((err = mod_hash_find(i_mactype_hash, (mod_hash_key_t)ident,
1863 	    (mod_hash_val_t *)&mtp)) != 0) {
1864 		/* A plugin is trying to unregister, but it never registered. */
1865 		err = ENXIO;
1866 		goto done;
1867 	}
1868 
1869 	if (mtp->mt_ref != 0) {
1870 		err = EBUSY;
1871 		goto done;
1872 	}
1873 
1874 	err = mod_hash_remove(i_mactype_hash, (mod_hash_key_t)ident, &val);
1875 	ASSERT(err == 0);
1876 	if (err != 0) {
1877 		/* This should never happen, thus the ASSERT() above. */
1878 		err = EINVAL;
1879 		goto done;
1880 	}
1881 	ASSERT(mtp == (mactype_t *)val);
1882 
1883 	kmem_free(mtp->mt_brdcst_addr, mtp->mt_addr_length);
1884 	kmem_free(mtp, sizeof (mactype_t));
1885 done:
1886 	mutex_exit(&i_mactype_lock);
1887 	return (err);
1888 }
1889