xref: /illumos-gate/usr/src/uts/common/io/mac/mac.c (revision 0173c38a73f34277e0c97a19fedfd25d81ba8380)
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 int
1038 mac_register(mac_register_t *mregp, mac_handle_t *mhp)
1039 {
1040 	mac_impl_t	*mip;
1041 	mactype_t	*mtype;
1042 	int		err;
1043 	struct devnames *dnp;
1044 	minor_t		minor;
1045 	mod_hash_val_t	val;
1046 	boolean_t	style1_created = B_FALSE, style2_created = B_FALSE;
1047 
1048 	/* Find the required MAC-Type plugin. */
1049 	if ((mtype = i_mactype_getplugin(mregp->m_type_ident)) == NULL)
1050 		return (EINVAL);
1051 
1052 	/* Create a mac_impl_t to represent this MAC. */
1053 	mip = kmem_cache_alloc(i_mac_impl_cachep, KM_SLEEP);
1054 
1055 	/*
1056 	 * The mac is not ready for open yet.
1057 	 */
1058 	mip->mi_disabled = B_TRUE;
1059 
1060 	mip->mi_drvname = ddi_driver_name(mregp->m_dip);
1061 	/*
1062 	 * Some drivers such as aggr need to register multiple MACs.  Such
1063 	 * drivers must supply a non-zero "instance" argument so that each
1064 	 * MAC can be assigned a unique MAC name and can have unique
1065 	 * kstats.
1066 	 */
1067 	mip->mi_instance = ((mregp->m_instance == 0) ?
1068 	    ddi_get_instance(mregp->m_dip) : mregp->m_instance);
1069 
1070 	/* Construct the MAC name as <drvname><instance> */
1071 	(void) snprintf(mip->mi_name, sizeof (mip->mi_name), "%s%d",
1072 	    mip->mi_drvname, mip->mi_instance);
1073 
1074 	rw_enter(&i_mac_impl_lock, RW_WRITER);
1075 	if (mod_hash_insert(i_mac_impl_hash,
1076 	    (mod_hash_key_t)mip->mi_name, (mod_hash_val_t)mip) != 0) {
1077 		kmem_cache_free(i_mac_impl_cachep, mip);
1078 		rw_exit(&i_mac_impl_lock);
1079 		return (EEXIST);
1080 	}
1081 	i_mac_impl_count++;
1082 
1083 	mip->mi_driver = mregp->m_driver;
1084 
1085 	mip->mi_type = mtype;
1086 
1087 	mip->mi_info.mi_media = mtype->mt_type;
1088 	mip->mi_info.mi_sdu_min = mregp->m_min_sdu;
1089 	if (mregp->m_max_sdu <= mregp->m_min_sdu) {
1090 		err = EINVAL;
1091 		goto fail;
1092 	}
1093 	mip->mi_info.mi_sdu_max = mregp->m_max_sdu;
1094 	mip->mi_info.mi_addr_length = mip->mi_type->mt_addr_length;
1095 	/*
1096 	 * If the media supports a broadcast address, cache a pointer to it
1097 	 * in the mac_info_t so that upper layers can use it.
1098 	 */
1099 	mip->mi_info.mi_brdcst_addr = mip->mi_type->mt_brdcst_addr;
1100 
1101 	/*
1102 	 * Copy the unicast source address into the mac_info_t, but only if
1103 	 * the MAC-Type defines a non-zero address length.  We need to
1104 	 * handle MAC-Types that have an address length of 0
1105 	 * (point-to-point protocol MACs for example).
1106 	 */
1107 	if (mip->mi_type->mt_addr_length > 0) {
1108 		if (mregp->m_src_addr == NULL) {
1109 			err = EINVAL;
1110 			goto fail;
1111 		}
1112 		mip->mi_info.mi_unicst_addr =
1113 		    kmem_alloc(mip->mi_type->mt_addr_length, KM_SLEEP);
1114 		bcopy(mregp->m_src_addr, mip->mi_info.mi_unicst_addr,
1115 		    mip->mi_type->mt_addr_length);
1116 
1117 		/*
1118 		 * Copy the fixed 'factory' MAC address from the immutable
1119 		 * info.  This is taken to be the MAC address currently in
1120 		 * use.
1121 		 */
1122 		bcopy(mip->mi_info.mi_unicst_addr, mip->mi_addr,
1123 		    mip->mi_type->mt_addr_length);
1124 		/* Copy the destination address if one is provided. */
1125 		if (mregp->m_dst_addr != NULL) {
1126 			bcopy(mregp->m_dst_addr, mip->mi_dstaddr,
1127 			    mip->mi_type->mt_addr_length);
1128 		}
1129 	} else if (mregp->m_src_addr != NULL) {
1130 		err = EINVAL;
1131 		goto fail;
1132 	}
1133 
1134 	/*
1135 	 * The format of the m_pdata is specific to the plugin.  It is
1136 	 * passed in as an argument to all of the plugin callbacks.  The
1137 	 * driver can update this information by calling
1138 	 * mac_pdata_update().
1139 	 */
1140 	if (mregp->m_pdata != NULL) {
1141 		/*
1142 		 * Verify that the plugin supports MAC plugin data and that
1143 		 * the supplied data is valid.
1144 		 */
1145 		if (!(mip->mi_type->mt_ops.mtops_ops & MTOPS_PDATA_VERIFY)) {
1146 			err = EINVAL;
1147 			goto fail;
1148 		}
1149 		if (!mip->mi_type->mt_ops.mtops_pdata_verify(mregp->m_pdata,
1150 		    mregp->m_pdata_size)) {
1151 			err = EINVAL;
1152 			goto fail;
1153 		}
1154 		mip->mi_pdata = kmem_alloc(mregp->m_pdata_size, KM_SLEEP);
1155 		bcopy(mregp->m_pdata, mip->mi_pdata, mregp->m_pdata_size);
1156 		mip->mi_pdata_size = mregp->m_pdata_size;
1157 	}
1158 
1159 	/*
1160 	 * Stash the driver callbacks into the mac_impl_t, but first sanity
1161 	 * check to make sure all mandatory callbacks are set.
1162 	 */
1163 	if (mregp->m_callbacks->mc_getstat == NULL ||
1164 	    mregp->m_callbacks->mc_start == NULL ||
1165 	    mregp->m_callbacks->mc_stop == NULL ||
1166 	    mregp->m_callbacks->mc_setpromisc == NULL ||
1167 	    mregp->m_callbacks->mc_multicst == NULL ||
1168 	    mregp->m_callbacks->mc_unicst == NULL ||
1169 	    mregp->m_callbacks->mc_tx == NULL) {
1170 		err = EINVAL;
1171 		goto fail;
1172 	}
1173 	mip->mi_callbacks = mregp->m_callbacks;
1174 
1175 	mip->mi_dip = mregp->m_dip;
1176 
1177 	/*
1178 	 * Set up the two possible transmit routines.
1179 	 */
1180 	mip->mi_txinfo.mt_fn = mip->mi_tx;
1181 	mip->mi_txinfo.mt_arg = mip->mi_driver;
1182 	mip->mi_txloopinfo.mt_fn = mac_txloop;
1183 	mip->mi_txloopinfo.mt_arg = mip;
1184 
1185 	/*
1186 	 * Initialize the kstats for this device.
1187 	 */
1188 	mac_stat_create(mip);
1189 
1190 	err = EEXIST;
1191 	/* Create a style-2 DLPI device */
1192 	if (ddi_create_minor_node(mip->mi_dip, (char *)mip->mi_drvname,
1193 	    S_IFCHR, 0, DDI_NT_NET, CLONE_DEV) != DDI_SUCCESS)
1194 		goto fail;
1195 	style2_created = B_TRUE;
1196 
1197 	/* Create a style-1 DLPI device */
1198 	minor = (minor_t)mip->mi_instance + 1;
1199 	if (ddi_create_minor_node(mip->mi_dip, mip->mi_name, S_IFCHR, minor,
1200 	    DDI_NT_NET, 0) != DDI_SUCCESS)
1201 		goto fail;
1202 	style1_created = B_TRUE;
1203 
1204 	/*
1205 	 * Create a link for this MAC.  The link name will be the same as
1206 	 * the MAC name.
1207 	 */
1208 	err = dls_create(mip->mi_name, mip->mi_name,
1209 	    ddi_get_instance(mip->mi_dip));
1210 	if (err != 0)
1211 		goto fail;
1212 
1213 	/* set the gldv3 flag in dn_flags */
1214 	dnp = &devnamesp[ddi_driver_major(mip->mi_dip)];
1215 	LOCK_DEV_OPS(&dnp->dn_lock);
1216 	dnp->dn_flags |= DN_GLDV3_DRIVER;
1217 	UNLOCK_DEV_OPS(&dnp->dn_lock);
1218 
1219 	/*
1220 	 * Mark the MAC to be ready for open.
1221 	 */
1222 	mip->mi_disabled = B_FALSE;
1223 
1224 	cmn_err(CE_NOTE, "!%s registered", mip->mi_name);
1225 	rw_exit(&i_mac_impl_lock);
1226 	*mhp = (mac_handle_t)mip;
1227 	return (0);
1228 
1229 fail:
1230 	(void) mod_hash_remove(i_mac_impl_hash, (mod_hash_key_t)mip->mi_name,
1231 	    &val);
1232 	ASSERT(mip == (mac_impl_t *)val);
1233 	i_mac_impl_count--;
1234 
1235 	if (mip->mi_info.mi_unicst_addr != NULL) {
1236 		kmem_free(mip->mi_info.mi_unicst_addr,
1237 		    mip->mi_type->mt_addr_length);
1238 		mip->mi_info.mi_unicst_addr = NULL;
1239 	}
1240 	if (style1_created)
1241 		ddi_remove_minor_node(mip->mi_dip, mip->mi_name);
1242 	if (style2_created)
1243 		ddi_remove_minor_node(mip->mi_dip, (char *)mip->mi_drvname);
1244 
1245 	mac_stat_destroy(mip);
1246 
1247 	if (mip->mi_type != NULL) {
1248 		mip->mi_type->mt_ref--;
1249 		mip->mi_type = NULL;
1250 	}
1251 
1252 	if (mip->mi_pdata != NULL) {
1253 		kmem_free(mip->mi_pdata, mip->mi_pdata_size);
1254 		mip->mi_pdata = NULL;
1255 		mip->mi_pdata_size = 0;
1256 	}
1257 
1258 	kmem_cache_free(i_mac_impl_cachep, mip);
1259 	rw_exit(&i_mac_impl_lock);
1260 	return (err);
1261 }
1262 
1263 int
1264 mac_unregister(mac_handle_t mh)
1265 {
1266 	int			err;
1267 	mac_impl_t		*mip = (mac_impl_t *)mh;
1268 	mod_hash_val_t		val;
1269 	mac_multicst_addr_t	*p, *nextp;
1270 
1271 	/*
1272 	 * See if there are any other references to this mac_t (e.g., VLAN's).
1273 	 * If not, set mi_disabled to prevent any new VLAN's from being
1274 	 * created while we're destroying this mac.
1275 	 */
1276 	rw_enter(&i_mac_impl_lock, RW_WRITER);
1277 	if (mip->mi_ref > 0) {
1278 		rw_exit(&i_mac_impl_lock);
1279 		return (EBUSY);
1280 	}
1281 	mip->mi_disabled = B_TRUE;
1282 	rw_exit(&i_mac_impl_lock);
1283 
1284 	/*
1285 	 * Wait for all taskqs which process the mac notifications to finish.
1286 	 */
1287 	mutex_enter(&mip->mi_notify_ref_lock);
1288 	while (mip->mi_notify_ref != 0)
1289 		cv_wait(&mip->mi_notify_cv, &mip->mi_notify_ref_lock);
1290 	mutex_exit(&mip->mi_notify_ref_lock);
1291 
1292 	if ((err = dls_destroy(mip->mi_name)) != 0) {
1293 		rw_enter(&i_mac_impl_lock, RW_WRITER);
1294 		mip->mi_disabled = B_FALSE;
1295 		rw_exit(&i_mac_impl_lock);
1296 		return (err);
1297 	}
1298 
1299 	/*
1300 	 * Remove both style 1 and style 2 minor nodes
1301 	 */
1302 	ddi_remove_minor_node(mip->mi_dip, (char *)mip->mi_drvname);
1303 	ddi_remove_minor_node(mip->mi_dip, mip->mi_name);
1304 
1305 	ASSERT(!mip->mi_activelink);
1306 
1307 	mac_stat_destroy(mip);
1308 
1309 	(void) mod_hash_remove(i_mac_impl_hash, (mod_hash_key_t)mip->mi_name,
1310 	    &val);
1311 	ASSERT(mip == (mac_impl_t *)val);
1312 
1313 	ASSERT(i_mac_impl_count > 0);
1314 	i_mac_impl_count--;
1315 
1316 	if (mip->mi_pdata != NULL)
1317 		kmem_free(mip->mi_pdata, mip->mi_pdata_size);
1318 	mip->mi_pdata = NULL;
1319 	mip->mi_pdata_size = 0;
1320 
1321 	/*
1322 	 * Free the list of multicast addresses.
1323 	 */
1324 	for (p = mip->mi_mmap; p != NULL; p = nextp) {
1325 		nextp = p->mma_nextp;
1326 		kmem_free(p, sizeof (mac_multicst_addr_t));
1327 	}
1328 	mip->mi_mmap = NULL;
1329 
1330 	mip->mi_linkstate = LINK_STATE_UNKNOWN;
1331 	kmem_free(mip->mi_info.mi_unicst_addr, mip->mi_type->mt_addr_length);
1332 	mip->mi_info.mi_unicst_addr = NULL;
1333 
1334 	mip->mi_type->mt_ref--;
1335 	mip->mi_type = NULL;
1336 
1337 	cmn_err(CE_NOTE, "!%s unregistered", mip->mi_name);
1338 
1339 	kmem_cache_free(i_mac_impl_cachep, mip);
1340 
1341 	return (0);
1342 }
1343 
1344 void
1345 mac_rx(mac_handle_t mh, mac_resource_handle_t mrh, mblk_t *bp)
1346 {
1347 	mac_impl_t	*mip = (mac_impl_t *)mh;
1348 	mac_rx_fn_t	*mrfp;
1349 
1350 	/*
1351 	 * Call all registered receive functions.
1352 	 */
1353 	rw_enter(&mip->mi_rx_lock, RW_READER);
1354 	mrfp = mip->mi_mrfp;
1355 	if (mrfp == NULL) {
1356 		/* There are no registered receive functions. */
1357 		freemsgchain(bp);
1358 		rw_exit(&mip->mi_rx_lock);
1359 		return;
1360 	}
1361 	do {
1362 		mblk_t *recv_bp;
1363 
1364 		if (mrfp->mrf_nextp != NULL) {
1365 			/* XXX Do we bump a counter if copymsgchain() fails? */
1366 			recv_bp = copymsgchain(bp);
1367 		} else {
1368 			recv_bp = bp;
1369 		}
1370 		if (recv_bp != NULL)
1371 			mrfp->mrf_fn(mrfp->mrf_arg, mrh, recv_bp);
1372 		mrfp = mrfp->mrf_nextp;
1373 	} while (mrfp != NULL);
1374 	rw_exit(&mip->mi_rx_lock);
1375 }
1376 
1377 /*
1378  * Transmit function -- ONLY used when there are registered loopback listeners.
1379  */
1380 mblk_t *
1381 mac_txloop(void *arg, mblk_t *bp)
1382 {
1383 	mac_impl_t	*mip = arg;
1384 	mac_txloop_fn_t	*mtfp;
1385 	mblk_t		*loop_bp, *resid_bp, *next_bp;
1386 
1387 	while (bp != NULL) {
1388 		next_bp = bp->b_next;
1389 		bp->b_next = NULL;
1390 
1391 		if ((loop_bp = copymsg(bp)) == NULL)
1392 			goto noresources;
1393 
1394 		if ((resid_bp = mip->mi_tx(mip->mi_driver, bp)) != NULL) {
1395 			ASSERT(resid_bp == bp);
1396 			freemsg(loop_bp);
1397 			goto noresources;
1398 		}
1399 
1400 		rw_enter(&mip->mi_txloop_lock, RW_READER);
1401 		mtfp = mip->mi_mtfp;
1402 		while (mtfp != NULL && loop_bp != NULL) {
1403 			bp = loop_bp;
1404 
1405 			/* XXX counter bump if copymsg() fails? */
1406 			if (mtfp->mtf_nextp != NULL)
1407 				loop_bp = copymsg(bp);
1408 			else
1409 				loop_bp = NULL;
1410 
1411 			mtfp->mtf_fn(mtfp->mtf_arg, bp);
1412 			mtfp = mtfp->mtf_nextp;
1413 		}
1414 		rw_exit(&mip->mi_txloop_lock);
1415 
1416 		/*
1417 		 * It's possible we've raced with the disabling of promiscuous
1418 		 * mode, in which case we can discard our copy.
1419 		 */
1420 		if (loop_bp != NULL)
1421 			freemsg(loop_bp);
1422 
1423 		bp = next_bp;
1424 	}
1425 
1426 	return (NULL);
1427 
1428 noresources:
1429 	bp->b_next = next_bp;
1430 	return (bp);
1431 }
1432 
1433 void
1434 mac_link_update(mac_handle_t mh, link_state_t link)
1435 {
1436 	mac_impl_t	*mip = (mac_impl_t *)mh;
1437 
1438 	/*
1439 	 * Save the link state.
1440 	 */
1441 	mip->mi_linkstate = link;
1442 
1443 	/*
1444 	 * Send a MAC_NOTE_LINK notification.
1445 	 */
1446 	i_mac_notify(mip, MAC_NOTE_LINK);
1447 }
1448 
1449 void
1450 mac_unicst_update(mac_handle_t mh, const uint8_t *addr)
1451 {
1452 	mac_impl_t	*mip = (mac_impl_t *)mh;
1453 
1454 	if (mip->mi_type->mt_addr_length == 0)
1455 		return;
1456 
1457 	/*
1458 	 * Save the address.
1459 	 */
1460 	bcopy(addr, mip->mi_addr, mip->mi_type->mt_addr_length);
1461 
1462 	/*
1463 	 * Send a MAC_NOTE_UNICST notification.
1464 	 */
1465 	i_mac_notify(mip, MAC_NOTE_UNICST);
1466 }
1467 
1468 void
1469 mac_tx_update(mac_handle_t mh)
1470 {
1471 	/*
1472 	 * Send a MAC_NOTE_TX notification.
1473 	 */
1474 	i_mac_notify((mac_impl_t *)mh, MAC_NOTE_TX);
1475 }
1476 
1477 void
1478 mac_resource_update(mac_handle_t mh)
1479 {
1480 	/*
1481 	 * Send a MAC_NOTE_RESOURCE notification.
1482 	 */
1483 	i_mac_notify((mac_impl_t *)mh, MAC_NOTE_RESOURCE);
1484 }
1485 
1486 mac_resource_handle_t
1487 mac_resource_add(mac_handle_t mh, mac_resource_t *mrp)
1488 {
1489 	mac_impl_t		*mip = (mac_impl_t *)mh;
1490 	mac_resource_handle_t	mrh;
1491 	mac_resource_add_t	add;
1492 	void			*arg;
1493 
1494 	rw_enter(&mip->mi_resource_lock, RW_READER);
1495 	add = mip->mi_resource_add;
1496 	arg = mip->mi_resource_add_arg;
1497 
1498 	if (add != NULL)
1499 		mrh = add(arg, mrp);
1500 	else
1501 		mrh = NULL;
1502 	rw_exit(&mip->mi_resource_lock);
1503 
1504 	return (mrh);
1505 }
1506 
1507 int
1508 mac_pdata_update(mac_handle_t mh, void *mac_pdata, size_t dsize)
1509 {
1510 	mac_impl_t	*mip = (mac_impl_t *)mh;
1511 
1512 	/*
1513 	 * Verify that the plugin supports MAC plugin data and that the
1514 	 * supplied data is valid.
1515 	 */
1516 	if (!(mip->mi_type->mt_ops.mtops_ops & MTOPS_PDATA_VERIFY))
1517 		return (EINVAL);
1518 	if (!mip->mi_type->mt_ops.mtops_pdata_verify(mac_pdata, dsize))
1519 		return (EINVAL);
1520 
1521 	if (mip->mi_pdata != NULL)
1522 		kmem_free(mip->mi_pdata, mip->mi_pdata_size);
1523 
1524 	mip->mi_pdata = kmem_alloc(dsize, KM_SLEEP);
1525 	bcopy(mac_pdata, mip->mi_pdata, dsize);
1526 	mip->mi_pdata_size = dsize;
1527 
1528 	/*
1529 	 * Since the MAC plugin data is used to construct MAC headers that
1530 	 * were cached in fast-path headers, we need to flush fast-path
1531 	 * information for links associated with this mac.
1532 	 */
1533 	i_mac_notify(mip, MAC_NOTE_FASTPATH_FLUSH);
1534 	return (0);
1535 }
1536 
1537 void
1538 mac_multicst_refresh(mac_handle_t mh, mac_multicst_t refresh, void *arg,
1539     boolean_t add)
1540 {
1541 	mac_impl_t		*mip = (mac_impl_t *)mh;
1542 	mac_multicst_addr_t	*p;
1543 
1544 	/*
1545 	 * If no specific refresh function was given then default to the
1546 	 * driver's m_multicst entry point.
1547 	 */
1548 	if (refresh == NULL) {
1549 		refresh = mip->mi_multicst;
1550 		arg = mip->mi_driver;
1551 	}
1552 	ASSERT(refresh != NULL);
1553 
1554 	/*
1555 	 * Walk the multicast address list and call the refresh function for
1556 	 * each address.
1557 	 */
1558 	rw_enter(&(mip->mi_data_lock), RW_READER);
1559 	for (p = mip->mi_mmap; p != NULL; p = p->mma_nextp)
1560 		refresh(arg, add, p->mma_addr);
1561 	rw_exit(&(mip->mi_data_lock));
1562 }
1563 
1564 void
1565 mac_unicst_refresh(mac_handle_t mh, mac_unicst_t refresh, void *arg)
1566 {
1567 	mac_impl_t	*mip = (mac_impl_t *)mh;
1568 	/*
1569 	 * If no specific refresh function was given then default to the
1570 	 * driver's mi_unicst entry point.
1571 	 */
1572 	if (refresh == NULL) {
1573 		refresh = mip->mi_unicst;
1574 		arg = mip->mi_driver;
1575 	}
1576 	ASSERT(refresh != NULL);
1577 
1578 	/*
1579 	 * Call the refresh function with the current unicast address.
1580 	 */
1581 	refresh(arg, mip->mi_addr);
1582 }
1583 
1584 void
1585 mac_promisc_refresh(mac_handle_t mh, mac_setpromisc_t refresh, void *arg)
1586 {
1587 	mac_impl_t	*mip = (mac_impl_t *)mh;
1588 
1589 	/*
1590 	 * If no specific refresh function was given then default to the
1591 	 * driver's m_promisc entry point.
1592 	 */
1593 	if (refresh == NULL) {
1594 		refresh = mip->mi_setpromisc;
1595 		arg = mip->mi_driver;
1596 	}
1597 	ASSERT(refresh != NULL);
1598 
1599 	/*
1600 	 * Call the refresh function with the current promiscuity.
1601 	 */
1602 	refresh(arg, (mip->mi_devpromisc != 0));
1603 }
1604 
1605 boolean_t
1606 mac_active_set(mac_handle_t mh)
1607 {
1608 	mac_impl_t *mip = (mac_impl_t *)mh;
1609 
1610 	mutex_enter(&mip->mi_activelink_lock);
1611 	if (mip->mi_activelink) {
1612 		mutex_exit(&mip->mi_activelink_lock);
1613 		return (B_FALSE);
1614 	}
1615 	mip->mi_activelink = B_TRUE;
1616 	mutex_exit(&mip->mi_activelink_lock);
1617 	return (B_TRUE);
1618 }
1619 
1620 void
1621 mac_active_clear(mac_handle_t mh)
1622 {
1623 	mac_impl_t *mip = (mac_impl_t *)mh;
1624 
1625 	mutex_enter(&mip->mi_activelink_lock);
1626 	ASSERT(mip->mi_activelink);
1627 	mip->mi_activelink = B_FALSE;
1628 	mutex_exit(&mip->mi_activelink_lock);
1629 }
1630 
1631 /*
1632  * mac_info_get() is used for retrieving the mac_info when a DL_INFO_REQ is
1633  * issued before a DL_ATTACH_REQ. we walk the i_mac_impl_hash table and find
1634  * the first mac_impl_t with a matching driver name; then we copy its mac_info_t
1635  * to the caller. we do all this with i_mac_impl_lock held so the mac_impl_t
1636  * cannot disappear while we are accessing it.
1637  */
1638 typedef struct i_mac_info_state_s {
1639 	const char	*mi_name;
1640 	mac_info_t	*mi_infop;
1641 } i_mac_info_state_t;
1642 
1643 /*ARGSUSED*/
1644 static uint_t
1645 i_mac_info_walker(mod_hash_key_t key, mod_hash_val_t *val, void *arg)
1646 {
1647 	i_mac_info_state_t	*statep = arg;
1648 	mac_impl_t		*mip = (mac_impl_t *)val;
1649 
1650 	if (mip->mi_disabled)
1651 		return (MH_WALK_CONTINUE);
1652 
1653 	if (strcmp(statep->mi_name,
1654 	    ddi_driver_name(mip->mi_dip)) != 0)
1655 		return (MH_WALK_CONTINUE);
1656 
1657 	statep->mi_infop = &mip->mi_info;
1658 	return (MH_WALK_TERMINATE);
1659 }
1660 
1661 boolean_t
1662 mac_info_get(const char *name, mac_info_t *minfop)
1663 {
1664 	i_mac_info_state_t	state;
1665 
1666 	rw_enter(&i_mac_impl_lock, RW_READER);
1667 	state.mi_name = name;
1668 	state.mi_infop = NULL;
1669 	mod_hash_walk(i_mac_impl_hash, i_mac_info_walker, &state);
1670 	if (state.mi_infop == NULL) {
1671 		rw_exit(&i_mac_impl_lock);
1672 		return (B_FALSE);
1673 	}
1674 	*minfop = *state.mi_infop;
1675 	rw_exit(&i_mac_impl_lock);
1676 	return (B_TRUE);
1677 }
1678 
1679 boolean_t
1680 mac_capab_get(mac_handle_t mh, mac_capab_t cap, void *cap_data)
1681 {
1682 	mac_impl_t *mip = (mac_impl_t *)mh;
1683 
1684 	if (mip->mi_callbacks->mc_callbacks & MC_GETCAPAB)
1685 		return (mip->mi_getcapab(mip->mi_driver, cap, cap_data));
1686 	else
1687 		return (B_FALSE);
1688 }
1689 
1690 boolean_t
1691 mac_sap_verify(mac_handle_t mh, uint32_t sap, uint32_t *bind_sap)
1692 {
1693 	mac_impl_t	*mip = (mac_impl_t *)mh;
1694 	return (mip->mi_type->mt_ops.mtops_sap_verify(sap, bind_sap,
1695 	    mip->mi_pdata));
1696 }
1697 
1698 mblk_t *
1699 mac_header(mac_handle_t mh, const uint8_t *daddr, uint32_t sap, mblk_t *payload,
1700     size_t extra_len)
1701 {
1702 	mac_impl_t	*mip = (mac_impl_t *)mh;
1703 	return (mip->mi_type->mt_ops.mtops_header(mip->mi_addr, daddr, sap,
1704 	    mip->mi_pdata, payload, extra_len));
1705 }
1706 
1707 int
1708 mac_header_info(mac_handle_t mh, mblk_t *mp, mac_header_info_t *mhip)
1709 {
1710 	mac_impl_t	*mip = (mac_impl_t *)mh;
1711 	return (mip->mi_type->mt_ops.mtops_header_info(mp, mip->mi_pdata,
1712 	    mhip));
1713 }
1714 
1715 mblk_t *
1716 mac_header_cook(mac_handle_t mh, mblk_t *mp)
1717 {
1718 	mac_impl_t	*mip = (mac_impl_t *)mh;
1719 	if (mip->mi_type->mt_ops.mtops_ops & MTOPS_HEADER_COOK) {
1720 		if (DB_REF(mp) > 1) {
1721 			mblk_t *newmp = copymsg(mp);
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 			freemsg(mp);
1739 			mp = newmp;
1740 		}
1741 		return (mip->mi_type->mt_ops.mtops_header_uncook(mp,
1742 		    mip->mi_pdata));
1743 	}
1744 	return (mp);
1745 }
1746 
1747 void
1748 mac_init_ops(struct dev_ops *ops, const char *name)
1749 {
1750 	dld_init_ops(ops, name);
1751 }
1752 
1753 void
1754 mac_fini_ops(struct dev_ops *ops)
1755 {
1756 	dld_fini_ops(ops);
1757 }
1758 
1759 /*
1760  * MAC Type Plugin functions.
1761  */
1762 
1763 mactype_register_t *
1764 mactype_alloc(uint_t mactype_version)
1765 {
1766 	mactype_register_t *mtrp;
1767 
1768 	/*
1769 	 * Make sure there isn't a version mismatch between the plugin and
1770 	 * the framework.  In the future, if multiple versions are
1771 	 * supported, this check could become more sophisticated.
1772 	 */
1773 	if (mactype_version != MACTYPE_VERSION)
1774 		return (NULL);
1775 
1776 	mtrp = kmem_zalloc(sizeof (mactype_register_t), KM_SLEEP);
1777 	mtrp->mtr_version = mactype_version;
1778 	return (mtrp);
1779 }
1780 
1781 void
1782 mactype_free(mactype_register_t *mtrp)
1783 {
1784 	kmem_free(mtrp, sizeof (mactype_register_t));
1785 }
1786 
1787 int
1788 mactype_register(mactype_register_t *mtrp)
1789 {
1790 	mactype_t	*mtp;
1791 	mactype_ops_t	*ops = mtrp->mtr_ops;
1792 
1793 	/* Do some sanity checking before we register this MAC type. */
1794 	if (mtrp->mtr_ident == NULL || ops == NULL || mtrp->mtr_addrlen == 0)
1795 		return (EINVAL);
1796 
1797 	/*
1798 	 * Verify that all mandatory callbacks are set in the ops
1799 	 * vector.
1800 	 */
1801 	if (ops->mtops_unicst_verify == NULL ||
1802 	    ops->mtops_multicst_verify == NULL ||
1803 	    ops->mtops_sap_verify == NULL ||
1804 	    ops->mtops_header == NULL ||
1805 	    ops->mtops_header_info == NULL) {
1806 		return (EINVAL);
1807 	}
1808 
1809 	mtp = kmem_zalloc(sizeof (*mtp), KM_SLEEP);
1810 	mtp->mt_ident = mtrp->mtr_ident;
1811 	mtp->mt_ops = *ops;
1812 	mtp->mt_type = mtrp->mtr_mactype;
1813 	mtp->mt_addr_length = mtrp->mtr_addrlen;
1814 	if (mtrp->mtr_brdcst_addr != NULL) {
1815 		mtp->mt_brdcst_addr = kmem_alloc(mtrp->mtr_addrlen, KM_SLEEP);
1816 		bcopy(mtrp->mtr_brdcst_addr, mtp->mt_brdcst_addr,
1817 		    mtrp->mtr_addrlen);
1818 	}
1819 
1820 	mtp->mt_stats = mtrp->mtr_stats;
1821 	mtp->mt_statcount = mtrp->mtr_statcount;
1822 
1823 	/*
1824 	 * A MAC-Type plugin only registers when i_mactype_getplugin() does
1825 	 * an explicit modload() as a result of a driver requesting to use
1826 	 * that plugin in mac_register().  We pre-emptively set the initial
1827 	 * reference count to 1 here to prevent the plugin module from
1828 	 * unloading before the driver's mac_register() completes.  If we
1829 	 * were to initialize the reference count to 0, then there would be
1830 	 * a window during which the module could unload before the
1831 	 * reference count could be bumped up to 1.
1832 	 */
1833 	mtp->mt_ref = 1;
1834 
1835 	if (mod_hash_insert(i_mactype_hash,
1836 	    (mod_hash_key_t)mtp->mt_ident, (mod_hash_val_t)mtp) != 0) {
1837 		kmem_free(mtp->mt_brdcst_addr, mtp->mt_addr_length);
1838 		kmem_free(mtp, sizeof (*mtp));
1839 		return (EEXIST);
1840 	}
1841 	return (0);
1842 }
1843 
1844 int
1845 mactype_unregister(const char *ident)
1846 {
1847 	mactype_t	*mtp;
1848 	mod_hash_val_t	val;
1849 	int 		err;
1850 
1851 	/*
1852 	 * Let's not allow MAC drivers to use this plugin while we're
1853 	 * trying to unregister it...
1854 	 */
1855 	rw_enter(&i_mac_impl_lock, RW_WRITER);
1856 
1857 	if ((err = mod_hash_find(i_mactype_hash, (mod_hash_key_t)ident,
1858 	    (mod_hash_val_t *)&mtp)) != 0) {
1859 		/* A plugin is trying to unregister, but it never registered. */
1860 		rw_exit(&i_mac_impl_lock);
1861 		return (ENXIO);
1862 	}
1863 
1864 	if (mtp->mt_ref > 0) {
1865 		rw_exit(&i_mac_impl_lock);
1866 		return (EBUSY);
1867 	}
1868 
1869 	err = mod_hash_remove(i_mactype_hash, (mod_hash_key_t)ident, &val);
1870 	ASSERT(err == 0);
1871 	if (err != 0) {
1872 		/* This should never happen, thus the ASSERT() above. */
1873 		rw_exit(&i_mac_impl_lock);
1874 		return (EINVAL);
1875 	}
1876 	ASSERT(mtp == (mactype_t *)val);
1877 
1878 	kmem_free(mtp->mt_brdcst_addr, mtp->mt_addr_length);
1879 	kmem_free(mtp, sizeof (mactype_t));
1880 	rw_exit(&i_mac_impl_lock);
1881 
1882 	return (0);
1883 }
1884