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