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