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