xref: /titanic_41/usr/src/uts/common/io/mac/mac.c (revision a3c4695861e3f0a8d3706f77ccd53683cca48d67)
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 /*
23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * MAC Services Module
31  */
32 
33 #include <sys/types.h>
34 #include <sys/conf.h>
35 #include <sys/id_space.h>
36 #include <sys/stat.h>
37 #include <sys/mkdev.h>
38 #include <sys/stream.h>
39 #include <sys/strsun.h>
40 #include <sys/strsubr.h>
41 #include <sys/dlpi.h>
42 #include <sys/dls.h>
43 #include <sys/modhash.h>
44 #include <sys/vlan.h>
45 #include <sys/mac.h>
46 #include <sys/mac_impl.h>
47 #include <sys/dld.h>
48 #include <sys/modctl.h>
49 #include <sys/fs/dv_node.h>
50 #include <sys/thread.h>
51 #include <sys/proc.h>
52 #include <sys/callb.h>
53 #include <sys/cpuvar.h>
54 #include <sys/atomic.h>
55 #include <sys/sdt.h>
56 #include <inet/nd.h>
57 
58 #define	IMPL_HASHSZ	67	/* prime */
59 
60 static kmem_cache_t	*i_mac_impl_cachep;
61 static mod_hash_t	*i_mac_impl_hash;
62 krwlock_t		i_mac_impl_lock;
63 uint_t			i_mac_impl_count;
64 static kmem_cache_t	*mac_vnic_tx_cache;
65 static id_space_t	*minor_ids;
66 static uint32_t		minor_count;
67 
68 #define	MACTYPE_KMODDIR	"mac"
69 #define	MACTYPE_HASHSZ	67
70 static mod_hash_t	*i_mactype_hash;
71 /*
72  * i_mactype_lock synchronizes threads that obtain references to mactype_t
73  * structures through i_mactype_getplugin().
74  */
75 static kmutex_t		i_mactype_lock;
76 
77 static void i_mac_notify_thread(void *);
78 static mblk_t *mac_vnic_tx(void *, mblk_t *);
79 static mblk_t *mac_vnic_txloop(void *, mblk_t *);
80 
81 /*
82  * Private functions.
83  */
84 
85 /*ARGSUSED*/
86 static int
87 i_mac_constructor(void *buf, void *arg, int kmflag)
88 {
89 	mac_impl_t	*mip = buf;
90 
91 	bzero(buf, sizeof (mac_impl_t));
92 
93 	mip->mi_linkstate = LINK_STATE_UNKNOWN;
94 
95 	rw_init(&mip->mi_state_lock, NULL, RW_DRIVER, NULL);
96 	rw_init(&mip->mi_gen_lock, NULL, RW_DRIVER, NULL);
97 	rw_init(&mip->mi_data_lock, NULL, RW_DRIVER, NULL);
98 	rw_init(&mip->mi_notify_lock, NULL, RW_DRIVER, NULL);
99 	rw_init(&mip->mi_rx_lock, NULL, RW_DRIVER, NULL);
100 	rw_init(&mip->mi_tx_lock, NULL, RW_DRIVER, NULL);
101 	rw_init(&mip->mi_resource_lock, NULL, RW_DRIVER, NULL);
102 	mutex_init(&mip->mi_activelink_lock, NULL, MUTEX_DEFAULT, NULL);
103 	mutex_init(&mip->mi_notify_bits_lock, NULL, MUTEX_DRIVER, NULL);
104 	cv_init(&mip->mi_notify_cv, NULL, CV_DRIVER, NULL);
105 	mutex_init(&mip->mi_lock, NULL, MUTEX_DRIVER, NULL);
106 	cv_init(&mip->mi_rx_cv, NULL, CV_DRIVER, NULL);
107 	return (0);
108 }
109 
110 /*ARGSUSED*/
111 static void
112 i_mac_destructor(void *buf, void *arg)
113 {
114 	mac_impl_t	*mip = buf;
115 
116 	ASSERT(mip->mi_ref == 0);
117 	ASSERT(!mip->mi_exclusive);
118 	ASSERT(mip->mi_active == 0);
119 	ASSERT(mip->mi_linkstate == LINK_STATE_UNKNOWN);
120 	ASSERT(mip->mi_devpromisc == 0);
121 	ASSERT(mip->mi_promisc == 0);
122 	ASSERT(mip->mi_mmap == NULL);
123 	ASSERT(mip->mi_mmrp == NULL);
124 	ASSERT(mip->mi_mnfp == NULL);
125 	ASSERT(mip->mi_resource_add == NULL);
126 	ASSERT(mip->mi_ksp == NULL);
127 	ASSERT(mip->mi_kstat_count == 0);
128 	ASSERT(mip->mi_notify_bits == 0);
129 	ASSERT(mip->mi_notify_thread == NULL);
130 
131 	rw_destroy(&mip->mi_gen_lock);
132 	rw_destroy(&mip->mi_state_lock);
133 	rw_destroy(&mip->mi_data_lock);
134 	rw_destroy(&mip->mi_notify_lock);
135 	rw_destroy(&mip->mi_rx_lock);
136 	rw_destroy(&mip->mi_tx_lock);
137 	rw_destroy(&mip->mi_resource_lock);
138 	mutex_destroy(&mip->mi_activelink_lock);
139 	mutex_destroy(&mip->mi_notify_bits_lock);
140 	cv_destroy(&mip->mi_notify_cv);
141 	mutex_destroy(&mip->mi_lock);
142 	cv_destroy(&mip->mi_rx_cv);
143 }
144 
145 /*
146  * mac_vnic_tx_t kmem cache support functions.
147  */
148 
149 /* ARGSUSED */
150 static int
151 i_mac_vnic_tx_ctor(void *buf, void *arg, int mkflag)
152 {
153 	mac_vnic_tx_t *vnic_tx = buf;
154 
155 	bzero(buf, sizeof (mac_vnic_tx_t));
156 	mutex_init(&vnic_tx->mv_lock, NULL, MUTEX_DRIVER, NULL);
157 	cv_init(&vnic_tx->mv_cv, NULL, CV_DRIVER, NULL);
158 	return (0);
159 }
160 
161 /* ARGSUSED */
162 static void
163 i_mac_vnic_tx_dtor(void *buf, void *arg)
164 {
165 	mac_vnic_tx_t *vnic_tx = buf;
166 
167 	ASSERT(vnic_tx->mv_refs == 0);
168 	mutex_destroy(&vnic_tx->mv_lock);
169 	cv_destroy(&vnic_tx->mv_cv);
170 }
171 
172 static void
173 i_mac_notify(mac_impl_t *mip, mac_notify_type_t type)
174 {
175 	rw_enter(&i_mac_impl_lock, RW_READER);
176 	if (mip->mi_disabled)
177 		goto exit;
178 
179 	/*
180 	 * Guard against incorrect notifications.  (Running a newer
181 	 * mac client against an older implementation?)
182 	 */
183 	if (type >= MAC_NNOTE)
184 		goto exit;
185 
186 	mutex_enter(&mip->mi_notify_bits_lock);
187 	mip->mi_notify_bits |= (1 << type);
188 	cv_broadcast(&mip->mi_notify_cv);
189 	mutex_exit(&mip->mi_notify_bits_lock);
190 
191 exit:
192 	rw_exit(&i_mac_impl_lock);
193 }
194 
195 static void
196 i_mac_log_link_state(mac_impl_t *mip)
197 {
198 	/*
199 	 * If no change, then it is not interesting.
200 	 */
201 	if (mip->mi_lastlinkstate == mip->mi_linkstate)
202 		return;
203 
204 	switch (mip->mi_linkstate) {
205 	case LINK_STATE_UP:
206 		if (mip->mi_type->mt_ops.mtops_ops & MTOPS_LINK_DETAILS) {
207 			char det[200];
208 
209 			mip->mi_type->mt_ops.mtops_link_details(det,
210 			    sizeof (det), (mac_handle_t)mip, mip->mi_pdata);
211 
212 			cmn_err(CE_NOTE, "!%s link up, %s", mip->mi_name, det);
213 		} else {
214 			cmn_err(CE_NOTE, "!%s link up", mip->mi_name);
215 		}
216 		break;
217 
218 	case LINK_STATE_DOWN:
219 		/*
220 		 * Only transitions from UP to DOWN are interesting
221 		 */
222 		if (mip->mi_lastlinkstate != LINK_STATE_UNKNOWN)
223 			cmn_err(CE_NOTE, "!%s link down", mip->mi_name);
224 		break;
225 
226 	case LINK_STATE_UNKNOWN:
227 		/*
228 		 * This case is normally not interesting.
229 		 */
230 		break;
231 	}
232 	mip->mi_lastlinkstate = mip->mi_linkstate;
233 }
234 
235 static void
236 i_mac_notify_thread(void *arg)
237 {
238 	mac_impl_t	*mip = arg;
239 	callb_cpr_t	cprinfo;
240 
241 	CALLB_CPR_INIT(&cprinfo, &mip->mi_notify_bits_lock, callb_generic_cpr,
242 	    "i_mac_notify_thread");
243 
244 	mutex_enter(&mip->mi_notify_bits_lock);
245 	for (;;) {
246 		uint32_t	bits;
247 		uint32_t	type;
248 
249 		bits = mip->mi_notify_bits;
250 		if (bits == 0) {
251 			CALLB_CPR_SAFE_BEGIN(&cprinfo);
252 			cv_wait(&mip->mi_notify_cv, &mip->mi_notify_bits_lock);
253 			CALLB_CPR_SAFE_END(&cprinfo, &mip->mi_notify_bits_lock);
254 			continue;
255 		}
256 		mip->mi_notify_bits = 0;
257 
258 		if ((bits & (1 << MAC_NNOTE)) != 0) {
259 			/* request to quit */
260 			ASSERT(mip->mi_disabled);
261 			break;
262 		}
263 
264 		mutex_exit(&mip->mi_notify_bits_lock);
265 
266 		/*
267 		 * Log link changes.
268 		 */
269 		if ((bits & (1 << MAC_NOTE_LINK)) != 0)
270 			i_mac_log_link_state(mip);
271 
272 		/*
273 		 * Do notification callbacks for each notification type.
274 		 */
275 		for (type = 0; type < MAC_NNOTE; type++) {
276 			mac_notify_fn_t	*mnfp;
277 
278 			if ((bits & (1 << type)) == 0) {
279 				continue;
280 			}
281 
282 			/*
283 			 * Walk the list of notifications.
284 			 */
285 			rw_enter(&mip->mi_notify_lock, RW_READER);
286 			for (mnfp = mip->mi_mnfp; mnfp != NULL;
287 			    mnfp = mnfp->mnf_nextp) {
288 
289 				mnfp->mnf_fn(mnfp->mnf_arg, type);
290 			}
291 			rw_exit(&mip->mi_notify_lock);
292 		}
293 
294 		mutex_enter(&mip->mi_notify_bits_lock);
295 	}
296 
297 	mip->mi_notify_thread = NULL;
298 	cv_broadcast(&mip->mi_notify_cv);
299 
300 	CALLB_CPR_EXIT(&cprinfo);
301 
302 	thread_exit();
303 }
304 
305 static mactype_t *
306 i_mactype_getplugin(const char *pname)
307 {
308 	mactype_t	*mtype = NULL;
309 	boolean_t	tried_modload = B_FALSE;
310 
311 	mutex_enter(&i_mactype_lock);
312 
313 find_registered_mactype:
314 	if (mod_hash_find(i_mactype_hash, (mod_hash_key_t)pname,
315 	    (mod_hash_val_t *)&mtype) != 0) {
316 		if (!tried_modload) {
317 			/*
318 			 * If the plugin has not yet been loaded, then
319 			 * attempt to load it now.  If modload() succeeds,
320 			 * the plugin should have registered using
321 			 * mactype_register(), in which case we can go back
322 			 * and attempt to find it again.
323 			 */
324 			if (modload(MACTYPE_KMODDIR, (char *)pname) != -1) {
325 				tried_modload = B_TRUE;
326 				goto find_registered_mactype;
327 			}
328 		}
329 	} else {
330 		/*
331 		 * Note that there's no danger that the plugin we've loaded
332 		 * could be unloaded between the modload() step and the
333 		 * reference count bump here, as we're holding
334 		 * i_mactype_lock, which mactype_unregister() also holds.
335 		 */
336 		atomic_inc_32(&mtype->mt_ref);
337 	}
338 
339 	mutex_exit(&i_mactype_lock);
340 	return (mtype);
341 }
342 
343 /*
344  * Module initialization functions.
345  */
346 
347 void
348 mac_init(void)
349 {
350 	i_mac_impl_cachep = kmem_cache_create("mac_impl_cache",
351 	    sizeof (mac_impl_t), 0, i_mac_constructor, i_mac_destructor,
352 	    NULL, NULL, NULL, 0);
353 	ASSERT(i_mac_impl_cachep != NULL);
354 
355 	mac_vnic_tx_cache = kmem_cache_create("mac_vnic_tx_cache",
356 	    sizeof (mac_vnic_tx_t), 0, i_mac_vnic_tx_ctor, i_mac_vnic_tx_dtor,
357 	    NULL, NULL, NULL, 0);
358 	ASSERT(mac_vnic_tx_cache != NULL);
359 
360 	i_mac_impl_hash = mod_hash_create_extended("mac_impl_hash",
361 	    IMPL_HASHSZ, mod_hash_null_keydtor, mod_hash_null_valdtor,
362 	    mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP);
363 	rw_init(&i_mac_impl_lock, NULL, RW_DEFAULT, NULL);
364 	i_mac_impl_count = 0;
365 
366 	i_mactype_hash = mod_hash_create_extended("mactype_hash",
367 	    MACTYPE_HASHSZ,
368 	    mod_hash_null_keydtor, mod_hash_null_valdtor,
369 	    mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP);
370 
371 	/*
372 	 * Allocate an id space to manage minor numbers. The range of the
373 	 * space will be from MAC_MAX_MINOR+1 to MAXMIN32 (maximum legal
374 	 * minor number is MAXMIN, but id_t is type of integer and does not
375 	 * allow MAXMIN).
376 	 */
377 	minor_ids = id_space_create("mac_minor_ids", MAC_MAX_MINOR+1, MAXMIN32);
378 	ASSERT(minor_ids != NULL);
379 	minor_count = 0;
380 }
381 
382 int
383 mac_fini(void)
384 {
385 	if (i_mac_impl_count > 0 || minor_count > 0)
386 		return (EBUSY);
387 
388 	id_space_destroy(minor_ids);
389 
390 	mod_hash_destroy_hash(i_mac_impl_hash);
391 	rw_destroy(&i_mac_impl_lock);
392 
393 	kmem_cache_destroy(i_mac_impl_cachep);
394 	kmem_cache_destroy(mac_vnic_tx_cache);
395 
396 	mod_hash_destroy_hash(i_mactype_hash);
397 	return (0);
398 }
399 
400 /*
401  * Client functions.
402  */
403 
404 static int
405 mac_hold(const char *macname, mac_impl_t **pmip)
406 {
407 	mac_impl_t	*mip;
408 	int		err;
409 
410 	/*
411 	 * Check the device name length to make sure it won't overflow our
412 	 * buffer.
413 	 */
414 	if (strlen(macname) >= MAXNAMELEN)
415 		return (EINVAL);
416 
417 	/*
418 	 * Look up its entry in the global hash table.
419 	 */
420 	rw_enter(&i_mac_impl_lock, RW_WRITER);
421 	err = mod_hash_find(i_mac_impl_hash, (mod_hash_key_t)macname,
422 	    (mod_hash_val_t *)&mip);
423 
424 	if (err != 0) {
425 		rw_exit(&i_mac_impl_lock);
426 		return (ENOENT);
427 	}
428 
429 	if (mip->mi_disabled) {
430 		rw_exit(&i_mac_impl_lock);
431 		return (ENOENT);
432 	}
433 
434 	if (mip->mi_exclusive) {
435 		rw_exit(&i_mac_impl_lock);
436 		return (EBUSY);
437 	}
438 
439 	mip->mi_ref++;
440 	rw_exit(&i_mac_impl_lock);
441 
442 	*pmip = mip;
443 	return (0);
444 }
445 
446 static void
447 mac_rele(mac_impl_t *mip)
448 {
449 	rw_enter(&i_mac_impl_lock, RW_WRITER);
450 	ASSERT(mip->mi_ref != 0);
451 	if (--mip->mi_ref == 0)
452 		ASSERT(!mip->mi_activelink);
453 	rw_exit(&i_mac_impl_lock);
454 }
455 
456 int
457 mac_hold_exclusive(mac_handle_t mh)
458 {
459 	mac_impl_t	*mip = (mac_impl_t *)mh;
460 
461 	/*
462 	 * Look up its entry in the global hash table.
463 	 */
464 	rw_enter(&i_mac_impl_lock, RW_WRITER);
465 	if (mip->mi_disabled) {
466 		rw_exit(&i_mac_impl_lock);
467 		return (ENOENT);
468 	}
469 
470 	if (mip->mi_ref != 0) {
471 		rw_exit(&i_mac_impl_lock);
472 		return (EBUSY);
473 	}
474 
475 	ASSERT(!mip->mi_exclusive);
476 
477 	mip->mi_ref++;
478 	mip->mi_exclusive = B_TRUE;
479 	rw_exit(&i_mac_impl_lock);
480 	return (0);
481 }
482 
483 void
484 mac_rele_exclusive(mac_handle_t mh)
485 {
486 	mac_impl_t	*mip = (mac_impl_t *)mh;
487 
488 	/*
489 	 * Look up its entry in the global hash table.
490 	 */
491 	rw_enter(&i_mac_impl_lock, RW_WRITER);
492 	ASSERT(mip->mi_ref == 1 && mip->mi_exclusive);
493 	mip->mi_ref--;
494 	mip->mi_exclusive = B_FALSE;
495 	rw_exit(&i_mac_impl_lock);
496 }
497 
498 int
499 mac_open(const char *macname, mac_handle_t *mhp)
500 {
501 	mac_impl_t	*mip;
502 	int		err;
503 
504 	/*
505 	 * Look up its entry in the global hash table.
506 	 */
507 	if ((err = mac_hold(macname, &mip)) != 0)
508 		return (err);
509 
510 	rw_enter(&mip->mi_gen_lock, RW_WRITER);
511 
512 	if ((mip->mi_oref != 0) ||
513 	    !(mip->mi_callbacks->mc_callbacks & MC_OPEN)) {
514 		goto done;
515 	}
516 
517 	/*
518 	 * Note that we do not hold i_mac_impl_lock when calling the
519 	 * mc_open() callback function to avoid deadlock with the
520 	 * i_mac_notify() function.
521 	 */
522 	if ((err = mip->mi_open(mip->mi_driver)) != 0) {
523 		rw_exit(&mip->mi_gen_lock);
524 		mac_rele(mip);
525 		return (err);
526 	}
527 
528 done:
529 	mip->mi_oref++;
530 	rw_exit(&mip->mi_gen_lock);
531 	*mhp = (mac_handle_t)mip;
532 	return (0);
533 }
534 
535 int
536 mac_open_by_linkid(datalink_id_t linkid, mac_handle_t *mhp)
537 {
538 	dls_dl_handle_t	dlh;
539 	int		err;
540 
541 	if ((err = dls_devnet_hold_tmp(linkid, &dlh)) != 0)
542 		return (err);
543 
544 	if (dls_devnet_vid(dlh) != VLAN_ID_NONE) {
545 		err = EINVAL;
546 		goto done;
547 	}
548 
549 	err = mac_open(dls_devnet_mac(dlh), mhp);
550 
551 done:
552 	dls_devnet_rele_tmp(dlh);
553 	return (err);
554 }
555 
556 int
557 mac_open_by_linkname(const char *link, mac_handle_t *mhp)
558 {
559 	datalink_id_t	linkid;
560 	int		err;
561 
562 	if ((err = dls_mgmt_get_linkid(link, &linkid)) != 0)
563 		return (err);
564 	return (mac_open_by_linkid(linkid, mhp));
565 }
566 
567 void
568 mac_close(mac_handle_t mh)
569 {
570 	mac_impl_t	*mip = (mac_impl_t *)mh;
571 
572 	rw_enter(&mip->mi_gen_lock, RW_WRITER);
573 
574 	ASSERT(mip->mi_oref != 0);
575 	if (--mip->mi_oref == 0) {
576 		if ((mip->mi_callbacks->mc_callbacks & MC_CLOSE))
577 			mip->mi_close(mip->mi_driver);
578 	}
579 	rw_exit(&mip->mi_gen_lock);
580 
581 	mac_rele(mip);
582 }
583 
584 const mac_info_t *
585 mac_info(mac_handle_t mh)
586 {
587 	return (&((mac_impl_t *)mh)->mi_info);
588 }
589 
590 dev_info_t *
591 mac_devinfo_get(mac_handle_t mh)
592 {
593 	return (((mac_impl_t *)mh)->mi_dip);
594 }
595 
596 const char *
597 mac_name(mac_handle_t mh)
598 {
599 	return (((mac_impl_t *)mh)->mi_name);
600 }
601 
602 minor_t
603 mac_minor(mac_handle_t mh)
604 {
605 	return (((mac_impl_t *)mh)->mi_minor);
606 }
607 
608 uint64_t
609 mac_stat_get(mac_handle_t mh, uint_t stat)
610 {
611 	mac_impl_t	*mip = (mac_impl_t *)mh;
612 	uint64_t	val;
613 	int		ret;
614 
615 	/*
616 	 * The range of stat determines where it is maintained.  Stat
617 	 * values from 0 up to (but not including) MAC_STAT_MIN are
618 	 * mainteined by the mac module itself.  Everything else is
619 	 * maintained by the driver.
620 	 */
621 	if (stat < MAC_STAT_MIN) {
622 		/* These stats are maintained by the mac module itself. */
623 		switch (stat) {
624 		case MAC_STAT_LINK_STATE:
625 			return (mip->mi_linkstate);
626 		case MAC_STAT_LINK_UP:
627 			return (mip->mi_linkstate == LINK_STATE_UP);
628 		case MAC_STAT_PROMISC:
629 			return (mip->mi_devpromisc != 0);
630 		default:
631 			ASSERT(B_FALSE);
632 		}
633 	}
634 
635 	/*
636 	 * Call the driver to get the given statistic.
637 	 */
638 	ret = mip->mi_getstat(mip->mi_driver, stat, &val);
639 	if (ret != 0) {
640 		/*
641 		 * The driver doesn't support this statistic.  Get the
642 		 * statistic's default value.
643 		 */
644 		val = mac_stat_default(mip, stat);
645 	}
646 	return (val);
647 }
648 
649 int
650 mac_start(mac_handle_t mh)
651 {
652 	mac_impl_t	*mip = (mac_impl_t *)mh;
653 	int		err;
654 
655 	ASSERT(mip->mi_start != NULL);
656 
657 	rw_enter(&(mip->mi_state_lock), RW_WRITER);
658 
659 	/*
660 	 * Check whether the device is already started.
661 	 */
662 	if (mip->mi_active++ != 0) {
663 		/*
664 		 * It's already started so there's nothing more to do.
665 		 */
666 		err = 0;
667 		goto done;
668 	}
669 
670 	/*
671 	 * Start the device.
672 	 */
673 	if ((err = mip->mi_start(mip->mi_driver)) != 0)
674 		--mip->mi_active;
675 
676 done:
677 	rw_exit(&(mip->mi_state_lock));
678 	return (err);
679 }
680 
681 void
682 mac_stop(mac_handle_t mh)
683 {
684 	mac_impl_t	*mip = (mac_impl_t *)mh;
685 
686 	ASSERT(mip->mi_stop != NULL);
687 
688 	rw_enter(&(mip->mi_state_lock), RW_WRITER);
689 
690 	/*
691 	 * Check whether the device is still needed.
692 	 */
693 	ASSERT(mip->mi_active != 0);
694 	if (--mip->mi_active != 0) {
695 		/*
696 		 * It's still needed so there's nothing more to do.
697 		 */
698 		goto done;
699 	}
700 
701 	/*
702 	 * Stop the device.
703 	 */
704 	mip->mi_stop(mip->mi_driver);
705 
706 done:
707 	rw_exit(&(mip->mi_state_lock));
708 }
709 
710 int
711 mac_multicst_add(mac_handle_t mh, const uint8_t *addr)
712 {
713 	mac_impl_t		*mip = (mac_impl_t *)mh;
714 	mac_multicst_addr_t	**pp;
715 	mac_multicst_addr_t	*p;
716 	int			err;
717 
718 	ASSERT(mip->mi_multicst != NULL);
719 
720 	/*
721 	 * Verify the address.
722 	 */
723 	if ((err = mip->mi_type->mt_ops.mtops_multicst_verify(addr,
724 	    mip->mi_pdata)) != 0) {
725 		return (err);
726 	}
727 
728 	/*
729 	 * Check whether the given address is already enabled.
730 	 */
731 	rw_enter(&(mip->mi_data_lock), RW_WRITER);
732 	for (pp = &(mip->mi_mmap); (p = *pp) != NULL; pp = &(p->mma_nextp)) {
733 		if (bcmp(p->mma_addr, addr, mip->mi_type->mt_addr_length) ==
734 		    0) {
735 			/*
736 			 * The address is already enabled so just bump the
737 			 * reference count.
738 			 */
739 			p->mma_ref++;
740 			err = 0;
741 			goto done;
742 		}
743 	}
744 
745 	/*
746 	 * Allocate a new list entry.
747 	 */
748 	if ((p = kmem_zalloc(sizeof (mac_multicst_addr_t),
749 	    KM_NOSLEEP)) == NULL) {
750 		err = ENOMEM;
751 		goto done;
752 	}
753 
754 	/*
755 	 * Enable a new multicast address.
756 	 */
757 	if ((err = mip->mi_multicst(mip->mi_driver, B_TRUE, addr)) != 0) {
758 		kmem_free(p, sizeof (mac_multicst_addr_t));
759 		goto done;
760 	}
761 
762 	/*
763 	 * Add the address to the list of enabled addresses.
764 	 */
765 	bcopy(addr, p->mma_addr, mip->mi_type->mt_addr_length);
766 	p->mma_ref++;
767 	*pp = p;
768 
769 done:
770 	rw_exit(&(mip->mi_data_lock));
771 	return (err);
772 }
773 
774 int
775 mac_multicst_remove(mac_handle_t mh, const uint8_t *addr)
776 {
777 	mac_impl_t		*mip = (mac_impl_t *)mh;
778 	mac_multicst_addr_t	**pp;
779 	mac_multicst_addr_t	*p;
780 	int			err;
781 
782 	ASSERT(mip->mi_multicst != NULL);
783 
784 	/*
785 	 * Find the entry in the list for the given address.
786 	 */
787 	rw_enter(&(mip->mi_data_lock), RW_WRITER);
788 	for (pp = &(mip->mi_mmap); (p = *pp) != NULL; pp = &(p->mma_nextp)) {
789 		if (bcmp(p->mma_addr, addr, mip->mi_type->mt_addr_length) ==
790 		    0) {
791 			if (--p->mma_ref == 0)
792 				break;
793 
794 			/*
795 			 * There is still a reference to this address so
796 			 * there's nothing more to do.
797 			 */
798 			err = 0;
799 			goto done;
800 		}
801 	}
802 
803 	/*
804 	 * We did not find an entry for the given address so it is not
805 	 * currently enabled.
806 	 */
807 	if (p == NULL) {
808 		err = ENOENT;
809 		goto done;
810 	}
811 	ASSERT(p->mma_ref == 0);
812 
813 	/*
814 	 * Disable the multicast address.
815 	 */
816 	if ((err = mip->mi_multicst(mip->mi_driver, B_FALSE, addr)) != 0) {
817 		p->mma_ref++;
818 		goto done;
819 	}
820 
821 	/*
822 	 * Remove it from the list.
823 	 */
824 	*pp = p->mma_nextp;
825 	kmem_free(p, sizeof (mac_multicst_addr_t));
826 
827 done:
828 	rw_exit(&(mip->mi_data_lock));
829 	return (err);
830 }
831 
832 /*
833  * mac_unicst_verify: Verifies the passed address. It fails
834  * if the passed address is a group address or has incorrect length.
835  */
836 boolean_t
837 mac_unicst_verify(mac_handle_t mh, const uint8_t *addr, uint_t len)
838 {
839 	mac_impl_t	*mip = (mac_impl_t *)mh;
840 
841 	/*
842 	 * Verify the address.
843 	 */
844 	if ((len != mip->mi_type->mt_addr_length) ||
845 	    (mip->mi_type->mt_ops.mtops_unicst_verify(addr,
846 	    mip->mi_pdata)) != 0) {
847 		return (B_FALSE);
848 	} else {
849 		return (B_TRUE);
850 	}
851 }
852 
853 int
854 mac_unicst_set(mac_handle_t mh, const uint8_t *addr)
855 {
856 	mac_impl_t	*mip = (mac_impl_t *)mh;
857 	int		err;
858 	boolean_t	notify = B_FALSE;
859 
860 	ASSERT(mip->mi_unicst != NULL);
861 
862 	/*
863 	 * Verify the address.
864 	 */
865 	if ((err = mip->mi_type->mt_ops.mtops_unicst_verify(addr,
866 	    mip->mi_pdata)) != 0) {
867 		return (err);
868 	}
869 
870 	/*
871 	 * Program the new unicast address.
872 	 */
873 	rw_enter(&(mip->mi_data_lock), RW_WRITER);
874 
875 	/*
876 	 * If address doesn't change, do nothing.
877 	 * This check is necessary otherwise it may call into mac_unicst_set
878 	 * recursively.
879 	 */
880 	if (bcmp(addr, mip->mi_addr, mip->mi_type->mt_addr_length) == 0)
881 		goto done;
882 
883 	if ((err = mip->mi_unicst(mip->mi_driver, addr)) != 0)
884 		goto done;
885 
886 	/*
887 	 * Save the address and flag that we need to send a notification.
888 	 */
889 	bcopy(addr, mip->mi_addr, mip->mi_type->mt_addr_length);
890 	notify = B_TRUE;
891 
892 done:
893 	rw_exit(&(mip->mi_data_lock));
894 
895 	if (notify)
896 		i_mac_notify(mip, MAC_NOTE_UNICST);
897 
898 	return (err);
899 }
900 
901 void
902 mac_unicst_get(mac_handle_t mh, uint8_t *addr)
903 {
904 	mac_impl_t	*mip = (mac_impl_t *)mh;
905 
906 	/*
907 	 * Copy out the current unicast source address.
908 	 */
909 	rw_enter(&(mip->mi_data_lock), RW_READER);
910 	bcopy(mip->mi_addr, addr, mip->mi_type->mt_addr_length);
911 	rw_exit(&(mip->mi_data_lock));
912 }
913 
914 void
915 mac_dest_get(mac_handle_t mh, uint8_t *addr)
916 {
917 	mac_impl_t	*mip = (mac_impl_t *)mh;
918 
919 	/*
920 	 * Copy out the current destination address.
921 	 */
922 	rw_enter(&(mip->mi_data_lock), RW_READER);
923 	bcopy(mip->mi_dstaddr, addr, mip->mi_type->mt_addr_length);
924 	rw_exit(&(mip->mi_data_lock));
925 }
926 
927 int
928 mac_promisc_set(mac_handle_t mh, boolean_t on, mac_promisc_type_t ptype)
929 {
930 	mac_impl_t	*mip = (mac_impl_t *)mh;
931 	int		err = 0;
932 
933 	ASSERT(mip->mi_setpromisc != NULL);
934 	ASSERT(ptype == MAC_DEVPROMISC || ptype == MAC_PROMISC);
935 
936 	/*
937 	 * Determine whether we should enable or disable promiscuous mode.
938 	 * For details on the distinction between "device promiscuous mode"
939 	 * and "MAC promiscuous mode", see PSARC/2005/289.
940 	 */
941 	rw_enter(&(mip->mi_data_lock), RW_WRITER);
942 	if (on) {
943 		/*
944 		 * Enable promiscuous mode on the device if not yet enabled.
945 		 */
946 		if (mip->mi_devpromisc++ == 0) {
947 			err = mip->mi_setpromisc(mip->mi_driver, B_TRUE);
948 			if (err != 0) {
949 				mip->mi_devpromisc--;
950 				goto done;
951 			}
952 			i_mac_notify(mip, MAC_NOTE_DEVPROMISC);
953 		}
954 
955 		/*
956 		 * Enable promiscuous mode on the MAC if not yet enabled.
957 		 */
958 		if (ptype == MAC_PROMISC && mip->mi_promisc++ == 0)
959 			i_mac_notify(mip, MAC_NOTE_PROMISC);
960 	} else {
961 		if (mip->mi_devpromisc == 0) {
962 			err = EPROTO;
963 			goto done;
964 		}
965 		/*
966 		 * Disable promiscuous mode on the device if this is the last
967 		 * enabling.
968 		 */
969 		if (--mip->mi_devpromisc == 0) {
970 			err = mip->mi_setpromisc(mip->mi_driver, B_FALSE);
971 			if (err != 0) {
972 				mip->mi_devpromisc++;
973 				goto done;
974 			}
975 			i_mac_notify(mip, MAC_NOTE_DEVPROMISC);
976 		}
977 
978 		/*
979 		 * Disable promiscuous mode on the MAC if this is the last
980 		 * enabling.
981 		 */
982 		if (ptype == MAC_PROMISC && --mip->mi_promisc == 0)
983 			i_mac_notify(mip, MAC_NOTE_PROMISC);
984 	}
985 
986 done:
987 	rw_exit(&(mip->mi_data_lock));
988 	return (err);
989 }
990 
991 boolean_t
992 mac_promisc_get(mac_handle_t mh, mac_promisc_type_t ptype)
993 {
994 	mac_impl_t		*mip = (mac_impl_t *)mh;
995 
996 	ASSERT(ptype == MAC_DEVPROMISC || ptype == MAC_PROMISC);
997 
998 	/*
999 	 * Return the current promiscuity.
1000 	 */
1001 	if (ptype == MAC_DEVPROMISC)
1002 		return (mip->mi_devpromisc != 0);
1003 	else
1004 		return (mip->mi_promisc != 0);
1005 }
1006 
1007 void
1008 mac_sdu_get(mac_handle_t mh, uint_t *min_sdu, uint_t *max_sdu)
1009 {
1010 	mac_impl_t	*mip = (mac_impl_t *)mh;
1011 
1012 	if (min_sdu != NULL)
1013 		*min_sdu = mip->mi_sdu_min;
1014 	if (max_sdu != NULL)
1015 		*max_sdu = mip->mi_sdu_max;
1016 }
1017 
1018 void
1019 mac_resources(mac_handle_t mh)
1020 {
1021 	mac_impl_t	*mip = (mac_impl_t *)mh;
1022 
1023 	/*
1024 	 * If the driver supports resource registration, call the driver to
1025 	 * ask it to register its resources.
1026 	 */
1027 	if (mip->mi_callbacks->mc_callbacks & MC_RESOURCES)
1028 		mip->mi_resources(mip->mi_driver);
1029 }
1030 
1031 void
1032 mac_ioctl(mac_handle_t mh, queue_t *wq, mblk_t *bp)
1033 {
1034 	mac_impl_t	*mip = (mac_impl_t *)mh;
1035 	int		cmd;
1036 
1037 	if (mip->mi_callbacks->mc_callbacks & (MC_SETPROP|MC_GETPROP)) {
1038 		cmd = ((struct iocblk *)bp->b_rptr)->ioc_cmd;
1039 		if (cmd == ND_SET || cmd == ND_GET) {
1040 			/*
1041 			 * ndd ioctls are Obsolete
1042 			 */
1043 			cmn_err(CE_WARN,
1044 			    "The ndd commands are obsolete and may be removed "
1045 			    "in a future release of Solaris. "
1046 			    "Use dladm(1M) to manage driver tunables\n");
1047 		}
1048 	}
1049 	/*
1050 	 * Call the driver to handle the ioctl.  The driver may not support
1051 	 * any ioctls, in which case we reply with a NAK on its behalf.
1052 	 */
1053 	if (mip->mi_callbacks->mc_callbacks & MC_IOCTL)
1054 		mip->mi_ioctl(mip->mi_driver, wq, bp);
1055 	else
1056 		miocnak(wq, bp, 0, EINVAL);
1057 }
1058 
1059 const mac_txinfo_t *
1060 mac_do_tx_get(mac_handle_t mh, boolean_t is_vnic)
1061 {
1062 	mac_impl_t	*mip = (mac_impl_t *)mh;
1063 	mac_txinfo_t	*mtp;
1064 
1065 	/*
1066 	 * Grab the lock to prevent us from racing with MAC_PROMISC being
1067 	 * changed.  This is sufficient since MAC clients are careful to always
1068 	 * call mac_txloop_add() prior to enabling MAC_PROMISC, and to disable
1069 	 * MAC_PROMISC prior to calling mac_txloop_remove().
1070 	 */
1071 	rw_enter(&mip->mi_tx_lock, RW_READER);
1072 
1073 	if (mac_promisc_get(mh, MAC_PROMISC)) {
1074 		ASSERT(mip->mi_mtfp != NULL);
1075 		if (mip->mi_vnic_present && !is_vnic) {
1076 			mtp = &mip->mi_vnic_txloopinfo;
1077 		} else {
1078 			mtp = &mip->mi_txloopinfo;
1079 		}
1080 	} else {
1081 		if (mip->mi_vnic_present && !is_vnic) {
1082 			mtp = &mip->mi_vnic_txinfo;
1083 		} else {
1084 			/*
1085 			 * Note that we cannot ASSERT() that mip->mi_mtfp is
1086 			 * NULL, because to satisfy the above ASSERT(), we
1087 			 * have to disable MAC_PROMISC prior to calling
1088 			 * mac_txloop_remove().
1089 			 */
1090 			mtp = &mip->mi_txinfo;
1091 		}
1092 	}
1093 
1094 	rw_exit(&mip->mi_tx_lock);
1095 	return (mtp);
1096 }
1097 
1098 /*
1099  * Invoked by VNIC to obtain the transmit entry point.
1100  */
1101 const mac_txinfo_t *
1102 mac_vnic_tx_get(mac_handle_t mh)
1103 {
1104 	return (mac_do_tx_get(mh, B_TRUE));
1105 }
1106 
1107 /*
1108  * Invoked by any non-VNIC client to obtain the transmit entry point.
1109  * If a VNIC is present, the VNIC transmit function provided by the VNIC
1110  * will be returned to the MAC client.
1111  */
1112 const mac_txinfo_t *
1113 mac_tx_get(mac_handle_t mh)
1114 {
1115 	return (mac_do_tx_get(mh, B_FALSE));
1116 }
1117 
1118 link_state_t
1119 mac_link_get(mac_handle_t mh)
1120 {
1121 	return (((mac_impl_t *)mh)->mi_linkstate);
1122 }
1123 
1124 mac_notify_handle_t
1125 mac_notify_add(mac_handle_t mh, mac_notify_t notify, void *arg)
1126 {
1127 	mac_impl_t		*mip = (mac_impl_t *)mh;
1128 	mac_notify_fn_t		*mnfp;
1129 
1130 	mnfp = kmem_zalloc(sizeof (mac_notify_fn_t), KM_SLEEP);
1131 	mnfp->mnf_fn = notify;
1132 	mnfp->mnf_arg = arg;
1133 
1134 	/*
1135 	 * Add it to the head of the 'notify' callback list.
1136 	 */
1137 	rw_enter(&mip->mi_notify_lock, RW_WRITER);
1138 	mnfp->mnf_nextp = mip->mi_mnfp;
1139 	mip->mi_mnfp = mnfp;
1140 	rw_exit(&mip->mi_notify_lock);
1141 
1142 	return ((mac_notify_handle_t)mnfp);
1143 }
1144 
1145 void
1146 mac_notify_remove(mac_handle_t mh, mac_notify_handle_t mnh)
1147 {
1148 	mac_impl_t		*mip = (mac_impl_t *)mh;
1149 	mac_notify_fn_t		*mnfp = (mac_notify_fn_t *)mnh;
1150 	mac_notify_fn_t		**pp;
1151 	mac_notify_fn_t		*p;
1152 
1153 	/*
1154 	 * Search the 'notify' callback list for the function closure.
1155 	 */
1156 	rw_enter(&mip->mi_notify_lock, RW_WRITER);
1157 	for (pp = &(mip->mi_mnfp); (p = *pp) != NULL;
1158 	    pp = &(p->mnf_nextp)) {
1159 		if (p == mnfp)
1160 			break;
1161 	}
1162 	ASSERT(p != NULL);
1163 
1164 	/*
1165 	 * Remove it from the list.
1166 	 */
1167 	*pp = p->mnf_nextp;
1168 	rw_exit(&mip->mi_notify_lock);
1169 
1170 	/*
1171 	 * Free it.
1172 	 */
1173 	kmem_free(mnfp, sizeof (mac_notify_fn_t));
1174 }
1175 
1176 void
1177 mac_notify(mac_handle_t mh)
1178 {
1179 	mac_impl_t		*mip = (mac_impl_t *)mh;
1180 	mac_notify_type_t	type;
1181 
1182 	for (type = 0; type < MAC_NNOTE; type++)
1183 		i_mac_notify(mip, type);
1184 }
1185 
1186 /*
1187  * Register a receive function for this mac.
1188  * More information on this function's interaction with mac_rx()
1189  * can be found atop mac_rx().
1190  */
1191 mac_rx_handle_t
1192 mac_do_rx_add(mac_handle_t mh, mac_rx_t rx, void *arg, boolean_t is_active)
1193 {
1194 	mac_impl_t	*mip = (mac_impl_t *)mh;
1195 	mac_rx_fn_t	*mrfp;
1196 
1197 	mrfp = kmem_zalloc(sizeof (mac_rx_fn_t), KM_SLEEP);
1198 	mrfp->mrf_fn = rx;
1199 	mrfp->mrf_arg = arg;
1200 	mrfp->mrf_active = is_active;
1201 
1202 	/*
1203 	 * Add it to the head of the 'rx' callback list.
1204 	 */
1205 	rw_enter(&(mip->mi_rx_lock), RW_WRITER);
1206 
1207 	/*
1208 	 * mac_rx() will only call callbacks that are marked inuse.
1209 	 */
1210 	mrfp->mrf_inuse = B_TRUE;
1211 	mrfp->mrf_nextp = mip->mi_mrfp;
1212 
1213 	/*
1214 	 * mac_rx() could be traversing the remainder of the list
1215 	 * and miss the new callback we're adding here. This is not a problem
1216 	 * because we do not guarantee the callback to take effect immediately
1217 	 * after mac_rx_add() returns.
1218 	 */
1219 	mip->mi_mrfp = mrfp;
1220 	rw_exit(&(mip->mi_rx_lock));
1221 
1222 	return ((mac_rx_handle_t)mrfp);
1223 }
1224 
1225 mac_rx_handle_t
1226 mac_rx_add(mac_handle_t mh, mac_rx_t rx, void *arg)
1227 {
1228 	return (mac_do_rx_add(mh, rx, arg, B_FALSE));
1229 }
1230 
1231 mac_rx_handle_t
1232 mac_active_rx_add(mac_handle_t mh, mac_rx_t rx, void *arg)
1233 {
1234 	return (mac_do_rx_add(mh, rx, arg, B_TRUE));
1235 }
1236 
1237 /*
1238  * Unregister a receive function for this mac.
1239  * This function does not block if wait is B_FALSE. This is useful
1240  * for clients who call mac_rx_remove() from a non-blockable context.
1241  * More information on this function's interaction with mac_rx()
1242  * can be found atop mac_rx().
1243  */
1244 void
1245 mac_rx_remove(mac_handle_t mh, mac_rx_handle_t mrh, boolean_t wait)
1246 {
1247 	mac_impl_t		*mip = (mac_impl_t *)mh;
1248 	mac_rx_fn_t		*mrfp = (mac_rx_fn_t *)mrh;
1249 	mac_rx_fn_t		**pp;
1250 	mac_rx_fn_t		*p;
1251 
1252 	/*
1253 	 * Search the 'rx' callback list for the function closure.
1254 	 */
1255 	rw_enter(&mip->mi_rx_lock, RW_WRITER);
1256 	for (pp = &(mip->mi_mrfp); (p = *pp) != NULL; pp = &(p->mrf_nextp)) {
1257 		if (p == mrfp)
1258 			break;
1259 	}
1260 	ASSERT(p != NULL);
1261 
1262 	/*
1263 	 * If mac_rx() is running, mark callback for deletion
1264 	 * and return (if wait is false), or wait until mac_rx()
1265 	 * exits (if wait is true).
1266 	 */
1267 	if (mip->mi_rx_ref > 0) {
1268 		DTRACE_PROBE1(defer_delete, mac_impl_t *, mip);
1269 		p->mrf_inuse = B_FALSE;
1270 		mutex_enter(&mip->mi_lock);
1271 		mip->mi_rx_removed++;
1272 		mutex_exit(&mip->mi_lock);
1273 
1274 		rw_exit(&mip->mi_rx_lock);
1275 		if (wait)
1276 			mac_rx_remove_wait(mh);
1277 		return;
1278 	}
1279 
1280 	/* Remove it from the list. */
1281 	*pp = p->mrf_nextp;
1282 	kmem_free(mrfp, sizeof (mac_rx_fn_t));
1283 	rw_exit(&mip->mi_rx_lock);
1284 }
1285 
1286 /*
1287  * Wait for all pending callback removals to be completed by mac_rx().
1288  * Note that if we call mac_rx_remove() immediately before this, there is no
1289  * guarantee we would wait *only* on the callback that we specified.
1290  * mac_rx_remove() could have been called by other threads and we would have
1291  * to wait for other marked callbacks to be removed as well.
1292  */
1293 void
1294 mac_rx_remove_wait(mac_handle_t mh)
1295 {
1296 	mac_impl_t	*mip = (mac_impl_t *)mh;
1297 
1298 	mutex_enter(&mip->mi_lock);
1299 	while (mip->mi_rx_removed > 0) {
1300 		DTRACE_PROBE1(need_wait, mac_impl_t *, mip);
1301 		cv_wait(&mip->mi_rx_cv, &mip->mi_lock);
1302 	}
1303 	mutex_exit(&mip->mi_lock);
1304 }
1305 
1306 mac_txloop_handle_t
1307 mac_txloop_add(mac_handle_t mh, mac_txloop_t tx, void *arg)
1308 {
1309 	mac_impl_t	*mip = (mac_impl_t *)mh;
1310 	mac_txloop_fn_t	*mtfp;
1311 
1312 	mtfp = kmem_zalloc(sizeof (mac_txloop_fn_t), KM_SLEEP);
1313 	mtfp->mtf_fn = tx;
1314 	mtfp->mtf_arg = arg;
1315 
1316 	/*
1317 	 * Add it to the head of the 'tx' callback list.
1318 	 */
1319 	rw_enter(&(mip->mi_tx_lock), RW_WRITER);
1320 	mtfp->mtf_nextp = mip->mi_mtfp;
1321 	mip->mi_mtfp = mtfp;
1322 	rw_exit(&(mip->mi_tx_lock));
1323 
1324 	return ((mac_txloop_handle_t)mtfp);
1325 }
1326 
1327 /*
1328  * Unregister a transmit function for this mac.  This removes the function
1329  * from the list of transmit functions for this mac.
1330  */
1331 void
1332 mac_txloop_remove(mac_handle_t mh, mac_txloop_handle_t mth)
1333 {
1334 	mac_impl_t		*mip = (mac_impl_t *)mh;
1335 	mac_txloop_fn_t		*mtfp = (mac_txloop_fn_t *)mth;
1336 	mac_txloop_fn_t		**pp;
1337 	mac_txloop_fn_t		*p;
1338 
1339 	/*
1340 	 * Search the 'tx' callback list for the function.
1341 	 */
1342 	rw_enter(&(mip->mi_tx_lock), RW_WRITER);
1343 	for (pp = &(mip->mi_mtfp); (p = *pp) != NULL; pp = &(p->mtf_nextp)) {
1344 		if (p == mtfp)
1345 			break;
1346 	}
1347 	ASSERT(p != NULL);
1348 
1349 	/* Remove it from the list. */
1350 	*pp = p->mtf_nextp;
1351 	kmem_free(mtfp, sizeof (mac_txloop_fn_t));
1352 	rw_exit(&(mip->mi_tx_lock));
1353 }
1354 
1355 void
1356 mac_resource_set(mac_handle_t mh, mac_resource_add_t add, void *arg)
1357 {
1358 	mac_impl_t		*mip = (mac_impl_t *)mh;
1359 
1360 	/*
1361 	 * Update the 'resource_add' callbacks.
1362 	 */
1363 	rw_enter(&(mip->mi_resource_lock), RW_WRITER);
1364 	mip->mi_resource_add = add;
1365 	mip->mi_resource_add_arg = arg;
1366 	rw_exit(&(mip->mi_resource_lock));
1367 }
1368 
1369 /*
1370  * Driver support functions.
1371  */
1372 
1373 mac_register_t *
1374 mac_alloc(uint_t mac_version)
1375 {
1376 	mac_register_t *mregp;
1377 
1378 	/*
1379 	 * Make sure there isn't a version mismatch between the driver and
1380 	 * the framework.  In the future, if multiple versions are
1381 	 * supported, this check could become more sophisticated.
1382 	 */
1383 	if (mac_version != MAC_VERSION)
1384 		return (NULL);
1385 
1386 	mregp = kmem_zalloc(sizeof (mac_register_t), KM_SLEEP);
1387 	mregp->m_version = mac_version;
1388 	return (mregp);
1389 }
1390 
1391 void
1392 mac_free(mac_register_t *mregp)
1393 {
1394 	kmem_free(mregp, sizeof (mac_register_t));
1395 }
1396 
1397 /*
1398  * Allocate a minor number.
1399  */
1400 minor_t
1401 mac_minor_hold(boolean_t sleep)
1402 {
1403 	minor_t	minor;
1404 
1405 	/*
1406 	 * Grab a value from the arena.
1407 	 */
1408 	atomic_add_32(&minor_count, 1);
1409 
1410 	if (sleep)
1411 		minor = (uint_t)id_alloc(minor_ids);
1412 	else
1413 		minor = (uint_t)id_alloc_nosleep(minor_ids);
1414 
1415 	if (minor == 0) {
1416 		atomic_add_32(&minor_count, -1);
1417 		return (0);
1418 	}
1419 
1420 	return (minor);
1421 }
1422 
1423 /*
1424  * Release a previously allocated minor number.
1425  */
1426 void
1427 mac_minor_rele(minor_t minor)
1428 {
1429 	/*
1430 	 * Return the value to the arena.
1431 	 */
1432 	id_free(minor_ids, minor);
1433 	atomic_add_32(&minor_count, -1);
1434 }
1435 
1436 uint32_t
1437 mac_no_notification(mac_handle_t mh)
1438 {
1439 	mac_impl_t *mip = (mac_impl_t *)mh;
1440 	return (mip->mi_unsup_note);
1441 }
1442 
1443 boolean_t
1444 mac_is_legacy(mac_handle_t mh)
1445 {
1446 	mac_impl_t *mip = (mac_impl_t *)mh;
1447 	return (mip->mi_legacy);
1448 }
1449 
1450 /*
1451  * mac_register() is how drivers register new MACs with the GLDv3
1452  * framework.  The mregp argument is allocated by drivers using the
1453  * mac_alloc() function, and can be freed using mac_free() immediately upon
1454  * return from mac_register().  Upon success (0 return value), the mhp
1455  * opaque pointer becomes the driver's handle to its MAC interface, and is
1456  * the argument to all other mac module entry points.
1457  */
1458 int
1459 mac_register(mac_register_t *mregp, mac_handle_t *mhp)
1460 {
1461 	mac_impl_t		*mip;
1462 	mactype_t		*mtype;
1463 	int			err = EINVAL;
1464 	struct devnames		*dnp = NULL;
1465 	uint_t			instance;
1466 	boolean_t		style1_created = B_FALSE;
1467 	boolean_t		style2_created = B_FALSE;
1468 	mac_capab_legacy_t	legacy;
1469 	char			*driver;
1470 	minor_t			minor = 0;
1471 
1472 	/* Find the required MAC-Type plugin. */
1473 	if ((mtype = i_mactype_getplugin(mregp->m_type_ident)) == NULL)
1474 		return (EINVAL);
1475 
1476 	/* Create a mac_impl_t to represent this MAC. */
1477 	mip = kmem_cache_alloc(i_mac_impl_cachep, KM_SLEEP);
1478 
1479 	/*
1480 	 * The mac is not ready for open yet.
1481 	 */
1482 	mip->mi_disabled = B_TRUE;
1483 
1484 	/*
1485 	 * When a mac is registered, the m_instance field can be set to:
1486 	 *
1487 	 *  0:	Get the mac's instance number from m_dip.
1488 	 *	This is usually used for physical device dips.
1489 	 *
1490 	 *  [1 .. MAC_MAX_MINOR-1]: Use the value as the mac's instance number.
1491 	 *	For example, when an aggregation is created with the key option,
1492 	 *	"key" will be used as the instance number.
1493 	 *
1494 	 *  -1: Assign an instance number from [MAC_MAX_MINOR .. MAXMIN-1].
1495 	 *	This is often used when a MAC of a virtual link is registered
1496 	 *	(e.g., aggregation when "key" is not specified, or vnic).
1497 	 *
1498 	 * Note that the instance number is used to derive the mi_minor field
1499 	 * of mac_impl_t, which will then be used to derive the name of kstats
1500 	 * and the devfs nodes.  The first 2 cases are needed to preserve
1501 	 * backward compatibility.
1502 	 */
1503 	switch (mregp->m_instance) {
1504 	case 0:
1505 		instance = ddi_get_instance(mregp->m_dip);
1506 		break;
1507 	case ((uint_t)-1):
1508 		minor = mac_minor_hold(B_TRUE);
1509 		if (minor == 0) {
1510 			err = ENOSPC;
1511 			goto fail;
1512 		}
1513 		instance = minor - 1;
1514 		break;
1515 	default:
1516 		instance = mregp->m_instance;
1517 		if (instance >= MAC_MAX_MINOR) {
1518 			err = EINVAL;
1519 			goto fail;
1520 		}
1521 		break;
1522 	}
1523 
1524 	mip->mi_minor = (minor_t)(instance + 1);
1525 	mip->mi_dip = mregp->m_dip;
1526 
1527 	driver = (char *)ddi_driver_name(mip->mi_dip);
1528 
1529 	/* Construct the MAC name as <drvname><instance> */
1530 	(void) snprintf(mip->mi_name, sizeof (mip->mi_name), "%s%d",
1531 	    driver, instance);
1532 
1533 	mip->mi_driver = mregp->m_driver;
1534 
1535 	mip->mi_type = mtype;
1536 	mip->mi_margin = mregp->m_margin;
1537 	mip->mi_info.mi_media = mtype->mt_type;
1538 	mip->mi_info.mi_nativemedia = mtype->mt_nativetype;
1539 	if (mregp->m_max_sdu <= mregp->m_min_sdu)
1540 		goto fail;
1541 	mip->mi_sdu_min = mregp->m_min_sdu;
1542 	mip->mi_sdu_max = mregp->m_max_sdu;
1543 	mip->mi_info.mi_addr_length = mip->mi_type->mt_addr_length;
1544 	/*
1545 	 * If the media supports a broadcast address, cache a pointer to it
1546 	 * in the mac_info_t so that upper layers can use it.
1547 	 */
1548 	mip->mi_info.mi_brdcst_addr = mip->mi_type->mt_brdcst_addr;
1549 
1550 	/*
1551 	 * Copy the unicast source address into the mac_info_t, but only if
1552 	 * the MAC-Type defines a non-zero address length.  We need to
1553 	 * handle MAC-Types that have an address length of 0
1554 	 * (point-to-point protocol MACs for example).
1555 	 */
1556 	if (mip->mi_type->mt_addr_length > 0) {
1557 		if (mregp->m_src_addr == NULL)
1558 			goto fail;
1559 		mip->mi_info.mi_unicst_addr =
1560 		    kmem_alloc(mip->mi_type->mt_addr_length, KM_SLEEP);
1561 		bcopy(mregp->m_src_addr, mip->mi_info.mi_unicst_addr,
1562 		    mip->mi_type->mt_addr_length);
1563 
1564 		/*
1565 		 * Copy the fixed 'factory' MAC address from the immutable
1566 		 * info.  This is taken to be the MAC address currently in
1567 		 * use.
1568 		 */
1569 		bcopy(mip->mi_info.mi_unicst_addr, mip->mi_addr,
1570 		    mip->mi_type->mt_addr_length);
1571 		/* Copy the destination address if one is provided. */
1572 		if (mregp->m_dst_addr != NULL) {
1573 			bcopy(mregp->m_dst_addr, mip->mi_dstaddr,
1574 			    mip->mi_type->mt_addr_length);
1575 		}
1576 	} else if (mregp->m_src_addr != NULL) {
1577 		goto fail;
1578 	}
1579 
1580 	/*
1581 	 * The format of the m_pdata is specific to the plugin.  It is
1582 	 * passed in as an argument to all of the plugin callbacks.  The
1583 	 * driver can update this information by calling
1584 	 * mac_pdata_update().
1585 	 */
1586 	if (mregp->m_pdata != NULL) {
1587 		/*
1588 		 * Verify that the plugin supports MAC plugin data and that
1589 		 * the supplied data is valid.
1590 		 */
1591 		if (!(mip->mi_type->mt_ops.mtops_ops & MTOPS_PDATA_VERIFY))
1592 			goto fail;
1593 		if (!mip->mi_type->mt_ops.mtops_pdata_verify(mregp->m_pdata,
1594 		    mregp->m_pdata_size)) {
1595 			goto fail;
1596 		}
1597 		mip->mi_pdata = kmem_alloc(mregp->m_pdata_size, KM_SLEEP);
1598 		bcopy(mregp->m_pdata, mip->mi_pdata, mregp->m_pdata_size);
1599 		mip->mi_pdata_size = mregp->m_pdata_size;
1600 	}
1601 
1602 	/*
1603 	 * Stash the driver callbacks into the mac_impl_t, but first sanity
1604 	 * check to make sure all mandatory callbacks are set.
1605 	 */
1606 	if (mregp->m_callbacks->mc_getstat == NULL ||
1607 	    mregp->m_callbacks->mc_start == NULL ||
1608 	    mregp->m_callbacks->mc_stop == NULL ||
1609 	    mregp->m_callbacks->mc_setpromisc == NULL ||
1610 	    mregp->m_callbacks->mc_multicst == NULL ||
1611 	    mregp->m_callbacks->mc_unicst == NULL ||
1612 	    mregp->m_callbacks->mc_tx == NULL) {
1613 		goto fail;
1614 	}
1615 	mip->mi_callbacks = mregp->m_callbacks;
1616 
1617 	/*
1618 	 * Set up the possible transmit routines.
1619 	 */
1620 	mip->mi_txinfo.mt_fn = mip->mi_tx;
1621 	mip->mi_txinfo.mt_arg = mip->mi_driver;
1622 
1623 	mip->mi_legacy = mac_capab_get((mac_handle_t)mip,
1624 	    MAC_CAPAB_LEGACY, &legacy);
1625 
1626 	if (mip->mi_legacy) {
1627 		/*
1628 		 * Legacy device. Messages being sent will be looped back
1629 		 * by the underlying driver. Therefore the txloop function
1630 		 * pointer is the same as the tx function pointer.
1631 		 */
1632 		mip->mi_txloopinfo.mt_fn = mip->mi_txinfo.mt_fn;
1633 		mip->mi_txloopinfo.mt_arg = mip->mi_txinfo.mt_arg;
1634 		mip->mi_unsup_note = legacy.ml_unsup_note;
1635 		mip->mi_phy_dev = legacy.ml_dev;
1636 	} else {
1637 		/*
1638 		 * Normal device. The framework needs to do the loopback.
1639 		 */
1640 		mip->mi_txloopinfo.mt_fn = mac_txloop;
1641 		mip->mi_txloopinfo.mt_arg = mip;
1642 		mip->mi_unsup_note = 0;
1643 		mip->mi_phy_dev = makedevice(ddi_driver_major(mip->mi_dip),
1644 		    ddi_get_instance(mip->mi_dip) + 1);
1645 	}
1646 
1647 	mip->mi_vnic_txinfo.mt_fn = mac_vnic_tx;
1648 	mip->mi_vnic_txinfo.mt_arg = mip;
1649 
1650 	mip->mi_vnic_txloopinfo.mt_fn = mac_vnic_txloop;
1651 	mip->mi_vnic_txloopinfo.mt_arg = mip;
1652 
1653 	/*
1654 	 * Allocate a notification thread.
1655 	 */
1656 	mip->mi_notify_thread = thread_create(NULL, 0, i_mac_notify_thread,
1657 	    mip, 0, &p0, TS_RUN, minclsyspri);
1658 	if (mip->mi_notify_thread == NULL)
1659 		goto fail;
1660 
1661 	/*
1662 	 * Initialize the kstats for this device.
1663 	 */
1664 	mac_stat_create(mip);
1665 
1666 	/* set the gldv3 flag in dn_flags */
1667 	dnp = &devnamesp[ddi_driver_major(mip->mi_dip)];
1668 	LOCK_DEV_OPS(&dnp->dn_lock);
1669 	dnp->dn_flags |= (DN_GLDV3_DRIVER | DN_NETWORK_DRIVER);
1670 	UNLOCK_DEV_OPS(&dnp->dn_lock);
1671 
1672 	if (mip->mi_minor < MAC_MAX_MINOR + 1) {
1673 		/* Create a style-2 DLPI device */
1674 		if (ddi_create_minor_node(mip->mi_dip, driver, S_IFCHR, 0,
1675 		    DDI_NT_NET, CLONE_DEV) != DDI_SUCCESS)
1676 			goto fail;
1677 		style2_created = B_TRUE;
1678 
1679 		/* Create a style-1 DLPI device */
1680 		if (ddi_create_minor_node(mip->mi_dip, mip->mi_name, S_IFCHR,
1681 		    mip->mi_minor, DDI_NT_NET, 0) != DDI_SUCCESS)
1682 			goto fail;
1683 		style1_created = B_TRUE;
1684 	}
1685 
1686 	rw_enter(&i_mac_impl_lock, RW_WRITER);
1687 	if (mod_hash_insert(i_mac_impl_hash,
1688 	    (mod_hash_key_t)mip->mi_name, (mod_hash_val_t)mip) != 0) {
1689 
1690 		rw_exit(&i_mac_impl_lock);
1691 		err = EEXIST;
1692 		goto fail;
1693 	}
1694 
1695 	DTRACE_PROBE2(mac__register, struct devnames *, dnp,
1696 	    (mac_impl_t *), mip);
1697 
1698 	/*
1699 	 * Mark the MAC to be ready for open.
1700 	 */
1701 	mip->mi_disabled = B_FALSE;
1702 
1703 	rw_exit(&i_mac_impl_lock);
1704 
1705 	atomic_inc_32(&i_mac_impl_count);
1706 
1707 	cmn_err(CE_NOTE, "!%s registered", mip->mi_name);
1708 	*mhp = (mac_handle_t)mip;
1709 	return (0);
1710 
1711 fail:
1712 	if (style1_created)
1713 		ddi_remove_minor_node(mip->mi_dip, mip->mi_name);
1714 
1715 	if (style2_created)
1716 		ddi_remove_minor_node(mip->mi_dip, driver);
1717 
1718 	/* clean up notification thread */
1719 	if (mip->mi_notify_thread != NULL) {
1720 		mutex_enter(&mip->mi_notify_bits_lock);
1721 		mip->mi_notify_bits = (1 << MAC_NNOTE);
1722 		cv_broadcast(&mip->mi_notify_cv);
1723 		while (mip->mi_notify_bits != 0)
1724 			cv_wait(&mip->mi_notify_cv, &mip->mi_notify_bits_lock);
1725 		mutex_exit(&mip->mi_notify_bits_lock);
1726 	}
1727 
1728 	if (mip->mi_info.mi_unicst_addr != NULL) {
1729 		kmem_free(mip->mi_info.mi_unicst_addr,
1730 		    mip->mi_type->mt_addr_length);
1731 		mip->mi_info.mi_unicst_addr = NULL;
1732 	}
1733 
1734 	mac_stat_destroy(mip);
1735 
1736 	if (mip->mi_type != NULL) {
1737 		atomic_dec_32(&mip->mi_type->mt_ref);
1738 		mip->mi_type = NULL;
1739 	}
1740 
1741 	if (mip->mi_pdata != NULL) {
1742 		kmem_free(mip->mi_pdata, mip->mi_pdata_size);
1743 		mip->mi_pdata = NULL;
1744 		mip->mi_pdata_size = 0;
1745 	}
1746 
1747 	if (minor != 0) {
1748 		ASSERT(minor > MAC_MAX_MINOR);
1749 		mac_minor_rele(minor);
1750 	}
1751 
1752 	kmem_cache_free(i_mac_impl_cachep, mip);
1753 	return (err);
1754 }
1755 
1756 int
1757 mac_disable(mac_handle_t mh)
1758 {
1759 	mac_impl_t		*mip = (mac_impl_t *)mh;
1760 
1761 	/*
1762 	 * See if there are any other references to this mac_t (e.g., VLAN's).
1763 	 * If not, set mi_disabled to prevent any new VLAN's from being
1764 	 * created while we're destroying this mac.
1765 	 */
1766 	rw_enter(&i_mac_impl_lock, RW_WRITER);
1767 	if (mip->mi_ref > 0) {
1768 		rw_exit(&i_mac_impl_lock);
1769 		return (EBUSY);
1770 	}
1771 	mip->mi_disabled = B_TRUE;
1772 	rw_exit(&i_mac_impl_lock);
1773 	return (0);
1774 }
1775 
1776 int
1777 mac_unregister(mac_handle_t mh)
1778 {
1779 	int			err;
1780 	mac_impl_t		*mip = (mac_impl_t *)mh;
1781 	mod_hash_val_t		val;
1782 	mac_multicst_addr_t	*p, *nextp;
1783 	mac_margin_req_t	*mmr, *nextmmr;
1784 
1785 	/*
1786 	 * See if there are any other references to this mac_t (e.g., VLAN's).
1787 	 * If not, set mi_disabled to prevent any new VLAN's from being
1788 	 * created while we're destroying this mac. Once mac_disable() returns
1789 	 * 0, the rest of mac_unregister() stuff should continue without
1790 	 * returning an error.
1791 	 */
1792 	if (!mip->mi_disabled) {
1793 		if ((err = mac_disable(mh)) != 0)
1794 			return (err);
1795 	}
1796 
1797 	/*
1798 	 * Clean up notification thread (wait for it to exit).
1799 	 */
1800 	mutex_enter(&mip->mi_notify_bits_lock);
1801 	mip->mi_notify_bits = (1 << MAC_NNOTE);
1802 	cv_broadcast(&mip->mi_notify_cv);
1803 	while (mip->mi_notify_bits != 0)
1804 		cv_wait(&mip->mi_notify_cv, &mip->mi_notify_bits_lock);
1805 	mutex_exit(&mip->mi_notify_bits_lock);
1806 
1807 	if (mip->mi_minor < MAC_MAX_MINOR + 1) {
1808 		ddi_remove_minor_node(mip->mi_dip, mip->mi_name);
1809 		ddi_remove_minor_node(mip->mi_dip,
1810 		    (char *)ddi_driver_name(mip->mi_dip));
1811 	}
1812 
1813 	ASSERT(!mip->mi_activelink);
1814 
1815 	mac_stat_destroy(mip);
1816 
1817 	rw_enter(&i_mac_impl_lock, RW_WRITER);
1818 	(void) mod_hash_remove(i_mac_impl_hash,
1819 	    (mod_hash_key_t)mip->mi_name, &val);
1820 	ASSERT(mip == (mac_impl_t *)val);
1821 
1822 	ASSERT(i_mac_impl_count > 0);
1823 	atomic_dec_32(&i_mac_impl_count);
1824 	rw_exit(&i_mac_impl_lock);
1825 
1826 	if (mip->mi_pdata != NULL)
1827 		kmem_free(mip->mi_pdata, mip->mi_pdata_size);
1828 	mip->mi_pdata = NULL;
1829 	mip->mi_pdata_size = 0;
1830 
1831 	/*
1832 	 * Free the list of multicast addresses.
1833 	 */
1834 	for (p = mip->mi_mmap; p != NULL; p = nextp) {
1835 		nextp = p->mma_nextp;
1836 		kmem_free(p, sizeof (mac_multicst_addr_t));
1837 	}
1838 	mip->mi_mmap = NULL;
1839 
1840 	/*
1841 	 * Free the list of margin request.
1842 	 */
1843 	for (mmr = mip->mi_mmrp; mmr != NULL; mmr = nextmmr) {
1844 		nextmmr = mmr->mmr_nextp;
1845 		kmem_free(mmr, sizeof (mac_margin_req_t));
1846 	}
1847 	mip->mi_mmrp = NULL;
1848 
1849 	mip->mi_linkstate = LINK_STATE_UNKNOWN;
1850 	kmem_free(mip->mi_info.mi_unicst_addr, mip->mi_type->mt_addr_length);
1851 	mip->mi_info.mi_unicst_addr = NULL;
1852 
1853 	atomic_dec_32(&mip->mi_type->mt_ref);
1854 	mip->mi_type = NULL;
1855 
1856 	if (mip->mi_minor > MAC_MAX_MINOR)
1857 		mac_minor_rele(mip->mi_minor);
1858 
1859 	cmn_err(CE_NOTE, "!%s unregistered", mip->mi_name);
1860 
1861 	kmem_cache_free(i_mac_impl_cachep, mip);
1862 
1863 	return (0);
1864 }
1865 
1866 /*
1867  * To avoid potential deadlocks, mac_rx() releases mi_rx_lock
1868  * before invoking its list of upcalls. This introduces races with
1869  * mac_rx_remove() and mac_rx_add(), who can potentially modify the
1870  * upcall list while mi_rx_lock is not being held. The race with
1871  * mac_rx_remove() is handled by incrementing mi_rx_ref upon entering
1872  * mac_rx(); a non-zero mi_rx_ref would tell mac_rx_remove()
1873  * to not modify the list but instead mark an upcall for deletion.
1874  * before mac_rx() exits, mi_rx_ref is decremented and if it
1875  * is 0, the marked upcalls will be removed from the list and freed.
1876  * The race with mac_rx_add() is harmless because mac_rx_add() only
1877  * prepends to the list and since mac_rx() saves the list head
1878  * before releasing mi_rx_lock, any prepended upcall won't be seen
1879  * until the next packet chain arrives.
1880  *
1881  * To minimize lock contention between multiple parallel invocations
1882  * of mac_rx(), mi_rx_lock is acquired as a READER lock. The
1883  * use of atomic operations ensures the sanity of mi_rx_ref. mi_rx_lock
1884  * will be upgraded to WRITER mode when there are marked upcalls to be
1885  * cleaned.
1886  */
1887 static void
1888 mac_do_rx(mac_handle_t mh, mac_resource_handle_t mrh, mblk_t *mp_chain,
1889     boolean_t active_only)
1890 {
1891 	mac_impl_t	*mip = (mac_impl_t *)mh;
1892 	mblk_t		*bp = mp_chain;
1893 	mac_rx_fn_t	*mrfp;
1894 
1895 	/*
1896 	 * Call all registered receive functions.
1897 	 */
1898 	rw_enter(&mip->mi_rx_lock, RW_READER);
1899 	if ((mrfp = mip->mi_mrfp) == NULL) {
1900 		/* There are no registered receive functions. */
1901 		freemsgchain(bp);
1902 		rw_exit(&mip->mi_rx_lock);
1903 		return;
1904 	}
1905 	atomic_inc_32(&mip->mi_rx_ref);
1906 	rw_exit(&mip->mi_rx_lock);
1907 
1908 	/*
1909 	 * Call registered receive functions.
1910 	 */
1911 	do {
1912 		mblk_t *recv_bp;
1913 
1914 		if (active_only && !mrfp->mrf_active) {
1915 			mrfp = mrfp->mrf_nextp;
1916 			if (mrfp == NULL) {
1917 				/*
1918 				 * We hit the last receiver, but it's not
1919 				 * active.
1920 				 */
1921 				freemsgchain(bp);
1922 			}
1923 			continue;
1924 		}
1925 
1926 		recv_bp = (mrfp->mrf_nextp != NULL) ? copymsgchain(bp) : bp;
1927 		if (recv_bp != NULL) {
1928 			if (mrfp->mrf_inuse) {
1929 				/*
1930 				 * Send bp itself and keep the copy.
1931 				 * If there's only one active receiver,
1932 				 * it should get the original message,
1933 				 * tagged with the hardware checksum flags.
1934 				 */
1935 				mrfp->mrf_fn(mrfp->mrf_arg, mrh, bp);
1936 				bp = recv_bp;
1937 			} else {
1938 				freemsgchain(recv_bp);
1939 			}
1940 		}
1941 
1942 		mrfp = mrfp->mrf_nextp;
1943 	} while (mrfp != NULL);
1944 
1945 	rw_enter(&mip->mi_rx_lock, RW_READER);
1946 	if (atomic_dec_32_nv(&mip->mi_rx_ref) == 0 && mip->mi_rx_removed > 0) {
1947 		mac_rx_fn_t	**pp, *p;
1948 		uint32_t	cnt = 0;
1949 
1950 		DTRACE_PROBE1(delete_callbacks, mac_impl_t *, mip);
1951 
1952 		/*
1953 		 * Need to become exclusive before doing cleanup
1954 		 */
1955 		if (rw_tryupgrade(&mip->mi_rx_lock) == 0) {
1956 			rw_exit(&mip->mi_rx_lock);
1957 			rw_enter(&mip->mi_rx_lock, RW_WRITER);
1958 		}
1959 
1960 		/*
1961 		 * We return if another thread has already entered and cleaned
1962 		 * up the list.
1963 		 */
1964 		if (mip->mi_rx_ref > 0 || mip->mi_rx_removed == 0) {
1965 			rw_exit(&mip->mi_rx_lock);
1966 			return;
1967 		}
1968 
1969 		/*
1970 		 * Free removed callbacks.
1971 		 */
1972 		pp = &mip->mi_mrfp;
1973 		while (*pp != NULL) {
1974 			if (!(*pp)->mrf_inuse) {
1975 				p = *pp;
1976 				*pp = (*pp)->mrf_nextp;
1977 				kmem_free(p, sizeof (*p));
1978 				cnt++;
1979 				continue;
1980 			}
1981 			pp = &(*pp)->mrf_nextp;
1982 		}
1983 
1984 		/*
1985 		 * Wake up mac_rx_remove_wait()
1986 		 */
1987 		mutex_enter(&mip->mi_lock);
1988 		ASSERT(mip->mi_rx_removed == cnt);
1989 		mip->mi_rx_removed = 0;
1990 		cv_broadcast(&mip->mi_rx_cv);
1991 		mutex_exit(&mip->mi_lock);
1992 	}
1993 	rw_exit(&mip->mi_rx_lock);
1994 }
1995 
1996 void
1997 mac_rx(mac_handle_t mh, mac_resource_handle_t mrh, mblk_t *mp_chain)
1998 {
1999 	mac_do_rx(mh, mrh, mp_chain, B_FALSE);
2000 }
2001 
2002 /*
2003  * Send a packet chain up to the receive callbacks which declared
2004  * themselves as being active.
2005  */
2006 void
2007 mac_active_rx(void *arg, mac_resource_handle_t mrh, mblk_t *mp_chain)
2008 {
2009 	mac_do_rx(arg, mrh, mp_chain, B_TRUE);
2010 }
2011 
2012 /*
2013  * Function passed to the active client sharing a VNIC. This function
2014  * is returned by mac_tx_get() when a VNIC is present. It invokes
2015  * the VNIC transmit entry point which was specified by the VNIC when
2016  * it called mac_vnic_set(). The VNIC transmit entry point will
2017  * pass the packets to the local VNICs and/or to the underlying VNICs
2018  * if needed.
2019  */
2020 static mblk_t *
2021 mac_vnic_tx(void *arg, mblk_t *mp)
2022 {
2023 	mac_impl_t	*mip = arg;
2024 	mac_txinfo_t	*mtfp;
2025 	mac_vnic_tx_t	*mvt;
2026 
2027 	/*
2028 	 * There is a race between the notification of the VNIC
2029 	 * addition and removal, and the processing of the VNIC notification
2030 	 * by the MAC client. During this window, it is possible for
2031 	 * an active MAC client to contine invoking mac_vnic_tx() while
2032 	 * the VNIC has already been removed. So we cannot assume
2033 	 * that mi_vnic_present will always be true when mac_vnic_tx()
2034 	 * is invoked.
2035 	 */
2036 	rw_enter(&mip->mi_tx_lock, RW_READER);
2037 	if (!mip->mi_vnic_present) {
2038 		rw_exit(&mip->mi_tx_lock);
2039 		freemsgchain(mp);
2040 		return (NULL);
2041 	}
2042 
2043 	ASSERT(mip->mi_vnic_tx != NULL);
2044 	mvt = mip->mi_vnic_tx;
2045 	MAC_VNIC_TXINFO_REFHOLD(mvt);
2046 	rw_exit(&mip->mi_tx_lock);
2047 
2048 	mtfp = &mvt->mv_txinfo;
2049 	mtfp->mt_fn(mtfp->mt_arg, mp);
2050 
2051 	MAC_VNIC_TXINFO_REFRELE(mvt);
2052 	return (NULL);
2053 }
2054 
2055 /*
2056  * Transmit function -- ONLY used when there are registered loopback listeners.
2057  */
2058 mblk_t *
2059 mac_do_txloop(void *arg, mblk_t *bp, boolean_t call_vnic)
2060 {
2061 	mac_impl_t	*mip = arg;
2062 	mac_txloop_fn_t	*mtfp;
2063 	mblk_t		*loop_bp, *resid_bp, *next_bp;
2064 
2065 	if (call_vnic) {
2066 		/*
2067 		 * In promiscous mode, a copy of the sent packet will
2068 		 * be sent to the client's promiscous receive entry
2069 		 * points via mac_vnic_tx()->
2070 		 * mac_active_rx_promisc()->mac_rx_default().
2071 		 */
2072 		return (mac_vnic_tx(arg, bp));
2073 	}
2074 
2075 	while (bp != NULL) {
2076 		next_bp = bp->b_next;
2077 		bp->b_next = NULL;
2078 
2079 		if ((loop_bp = copymsg(bp)) == NULL)
2080 			goto noresources;
2081 
2082 		if ((resid_bp = mip->mi_tx(mip->mi_driver, bp)) != NULL) {
2083 			ASSERT(resid_bp == bp);
2084 			freemsg(loop_bp);
2085 			goto noresources;
2086 		}
2087 
2088 		rw_enter(&mip->mi_tx_lock, RW_READER);
2089 		mtfp = mip->mi_mtfp;
2090 		while (mtfp != NULL && loop_bp != NULL) {
2091 			bp = loop_bp;
2092 
2093 			/* XXX counter bump if copymsg() fails? */
2094 			if (mtfp->mtf_nextp != NULL)
2095 				loop_bp = copymsg(bp);
2096 			else
2097 				loop_bp = NULL;
2098 
2099 			mtfp->mtf_fn(mtfp->mtf_arg, bp);
2100 			mtfp = mtfp->mtf_nextp;
2101 		}
2102 		rw_exit(&mip->mi_tx_lock);
2103 
2104 		/*
2105 		 * It's possible we've raced with the disabling of promiscuous
2106 		 * mode, in which case we can discard our copy.
2107 		 */
2108 		if (loop_bp != NULL)
2109 			freemsg(loop_bp);
2110 
2111 		bp = next_bp;
2112 	}
2113 
2114 	return (NULL);
2115 
2116 noresources:
2117 	bp->b_next = next_bp;
2118 	return (bp);
2119 }
2120 
2121 mblk_t *
2122 mac_txloop(void *arg, mblk_t *bp)
2123 {
2124 	return (mac_do_txloop(arg, bp, B_FALSE));
2125 }
2126 
2127 static mblk_t *
2128 mac_vnic_txloop(void *arg, mblk_t *bp)
2129 {
2130 	return (mac_do_txloop(arg, bp, B_TRUE));
2131 }
2132 
2133 void
2134 mac_link_update(mac_handle_t mh, link_state_t link)
2135 {
2136 	mac_impl_t	*mip = (mac_impl_t *)mh;
2137 
2138 	/*
2139 	 * Save the link state.
2140 	 */
2141 	mip->mi_linkstate = link;
2142 
2143 	/*
2144 	 * Send a MAC_NOTE_LINK notification.
2145 	 */
2146 	i_mac_notify(mip, MAC_NOTE_LINK);
2147 }
2148 
2149 void
2150 mac_unicst_update(mac_handle_t mh, const uint8_t *addr)
2151 {
2152 	mac_impl_t	*mip = (mac_impl_t *)mh;
2153 
2154 	if (mip->mi_type->mt_addr_length == 0)
2155 		return;
2156 
2157 	/*
2158 	 * If the address has not changed, do nothing.
2159 	 */
2160 	if (bcmp(addr, mip->mi_addr, mip->mi_type->mt_addr_length) == 0)
2161 		return;
2162 
2163 	/*
2164 	 * Save the address.
2165 	 */
2166 	bcopy(addr, mip->mi_addr, mip->mi_type->mt_addr_length);
2167 
2168 	/*
2169 	 * Send a MAC_NOTE_UNICST notification.
2170 	 */
2171 	i_mac_notify(mip, MAC_NOTE_UNICST);
2172 }
2173 
2174 void
2175 mac_tx_update(mac_handle_t mh)
2176 {
2177 	/*
2178 	 * Send a MAC_NOTE_TX notification.
2179 	 */
2180 	i_mac_notify((mac_impl_t *)mh, MAC_NOTE_TX);
2181 }
2182 
2183 void
2184 mac_resource_update(mac_handle_t mh)
2185 {
2186 	/*
2187 	 * Send a MAC_NOTE_RESOURCE notification.
2188 	 */
2189 	i_mac_notify((mac_impl_t *)mh, MAC_NOTE_RESOURCE);
2190 }
2191 
2192 mac_resource_handle_t
2193 mac_resource_add(mac_handle_t mh, mac_resource_t *mrp)
2194 {
2195 	mac_impl_t		*mip = (mac_impl_t *)mh;
2196 	mac_resource_handle_t	mrh;
2197 	mac_resource_add_t	add;
2198 	void			*arg;
2199 
2200 	rw_enter(&mip->mi_resource_lock, RW_READER);
2201 	add = mip->mi_resource_add;
2202 	arg = mip->mi_resource_add_arg;
2203 
2204 	if (add != NULL)
2205 		mrh = add(arg, mrp);
2206 	else
2207 		mrh = NULL;
2208 	rw_exit(&mip->mi_resource_lock);
2209 
2210 	return (mrh);
2211 }
2212 
2213 int
2214 mac_pdata_update(mac_handle_t mh, void *mac_pdata, size_t dsize)
2215 {
2216 	mac_impl_t	*mip = (mac_impl_t *)mh;
2217 
2218 	/*
2219 	 * Verify that the plugin supports MAC plugin data and that the
2220 	 * supplied data is valid.
2221 	 */
2222 	if (!(mip->mi_type->mt_ops.mtops_ops & MTOPS_PDATA_VERIFY))
2223 		return (EINVAL);
2224 	if (!mip->mi_type->mt_ops.mtops_pdata_verify(mac_pdata, dsize))
2225 		return (EINVAL);
2226 
2227 	if (mip->mi_pdata != NULL)
2228 		kmem_free(mip->mi_pdata, mip->mi_pdata_size);
2229 
2230 	mip->mi_pdata = kmem_alloc(dsize, KM_SLEEP);
2231 	bcopy(mac_pdata, mip->mi_pdata, dsize);
2232 	mip->mi_pdata_size = dsize;
2233 
2234 	/*
2235 	 * Since the MAC plugin data is used to construct MAC headers that
2236 	 * were cached in fast-path headers, we need to flush fast-path
2237 	 * information for links associated with this mac.
2238 	 */
2239 	i_mac_notify(mip, MAC_NOTE_FASTPATH_FLUSH);
2240 	return (0);
2241 }
2242 
2243 void
2244 mac_multicst_refresh(mac_handle_t mh, mac_multicst_t refresh, void *arg,
2245     boolean_t add)
2246 {
2247 	mac_impl_t		*mip = (mac_impl_t *)mh;
2248 	mac_multicst_addr_t	*p;
2249 
2250 	/*
2251 	 * If no specific refresh function was given then default to the
2252 	 * driver's m_multicst entry point.
2253 	 */
2254 	if (refresh == NULL) {
2255 		refresh = mip->mi_multicst;
2256 		arg = mip->mi_driver;
2257 	}
2258 	ASSERT(refresh != NULL);
2259 
2260 	/*
2261 	 * Walk the multicast address list and call the refresh function for
2262 	 * each address.
2263 	 */
2264 	rw_enter(&(mip->mi_data_lock), RW_READER);
2265 	for (p = mip->mi_mmap; p != NULL; p = p->mma_nextp)
2266 		refresh(arg, add, p->mma_addr);
2267 	rw_exit(&(mip->mi_data_lock));
2268 }
2269 
2270 void
2271 mac_unicst_refresh(mac_handle_t mh, mac_unicst_t refresh, void *arg)
2272 {
2273 	mac_impl_t	*mip = (mac_impl_t *)mh;
2274 	/*
2275 	 * If no specific refresh function was given then default to the
2276 	 * driver's mi_unicst entry point.
2277 	 */
2278 	if (refresh == NULL) {
2279 		refresh = mip->mi_unicst;
2280 		arg = mip->mi_driver;
2281 	}
2282 	ASSERT(refresh != NULL);
2283 
2284 	/*
2285 	 * Call the refresh function with the current unicast address.
2286 	 */
2287 	refresh(arg, mip->mi_addr);
2288 }
2289 
2290 void
2291 mac_promisc_refresh(mac_handle_t mh, mac_setpromisc_t refresh, void *arg)
2292 {
2293 	mac_impl_t	*mip = (mac_impl_t *)mh;
2294 
2295 	/*
2296 	 * If no specific refresh function was given then default to the
2297 	 * driver's m_promisc entry point.
2298 	 */
2299 	if (refresh == NULL) {
2300 		refresh = mip->mi_setpromisc;
2301 		arg = mip->mi_driver;
2302 	}
2303 	ASSERT(refresh != NULL);
2304 
2305 	/*
2306 	 * Call the refresh function with the current promiscuity.
2307 	 */
2308 	refresh(arg, (mip->mi_devpromisc != 0));
2309 }
2310 
2311 /*
2312  * The mac client requests that the mac not to change its margin size to
2313  * be less than the specified value.  If "current" is B_TRUE, then the client
2314  * requests the mac not to change its margin size to be smaller than the
2315  * current size. Further, return the current margin size value in this case.
2316  *
2317  * We keep every requested size in an ordered list from largest to smallest.
2318  */
2319 int
2320 mac_margin_add(mac_handle_t mh, uint32_t *marginp, boolean_t current)
2321 {
2322 	mac_impl_t		*mip = (mac_impl_t *)mh;
2323 	mac_margin_req_t	**pp, *p;
2324 	int			err = 0;
2325 
2326 	rw_enter(&(mip->mi_data_lock), RW_WRITER);
2327 	if (current)
2328 		*marginp = mip->mi_margin;
2329 
2330 	/*
2331 	 * If the current margin value cannot satisfy the margin requested,
2332 	 * return ENOTSUP directly.
2333 	 */
2334 	if (*marginp > mip->mi_margin) {
2335 		err = ENOTSUP;
2336 		goto done;
2337 	}
2338 
2339 	/*
2340 	 * Check whether the given margin is already in the list. If so,
2341 	 * bump the reference count.
2342 	 */
2343 	for (pp = &(mip->mi_mmrp); (p = *pp) != NULL; pp = &(p->mmr_nextp)) {
2344 		if (p->mmr_margin == *marginp) {
2345 			/*
2346 			 * The margin requested is already in the list,
2347 			 * so just bump the reference count.
2348 			 */
2349 			p->mmr_ref++;
2350 			goto done;
2351 		}
2352 		if (p->mmr_margin < *marginp)
2353 			break;
2354 	}
2355 
2356 
2357 	if ((p = kmem_zalloc(sizeof (mac_margin_req_t), KM_NOSLEEP)) == NULL) {
2358 		err = ENOMEM;
2359 		goto done;
2360 	}
2361 
2362 	p->mmr_margin = *marginp;
2363 	p->mmr_ref++;
2364 	p->mmr_nextp = *pp;
2365 	*pp = p;
2366 
2367 done:
2368 	rw_exit(&(mip->mi_data_lock));
2369 	return (err);
2370 }
2371 
2372 /*
2373  * The mac client requests to cancel its previous mac_margin_add() request.
2374  * We remove the requested margin size from the list.
2375  */
2376 int
2377 mac_margin_remove(mac_handle_t mh, uint32_t margin)
2378 {
2379 	mac_impl_t		*mip = (mac_impl_t *)mh;
2380 	mac_margin_req_t	**pp, *p;
2381 	int			err = 0;
2382 
2383 	rw_enter(&(mip->mi_data_lock), RW_WRITER);
2384 	/*
2385 	 * Find the entry in the list for the given margin.
2386 	 */
2387 	for (pp = &(mip->mi_mmrp); (p = *pp) != NULL; pp = &(p->mmr_nextp)) {
2388 		if (p->mmr_margin == margin) {
2389 			if (--p->mmr_ref == 0)
2390 				break;
2391 
2392 			/*
2393 			 * There is still a reference to this address so
2394 			 * there's nothing more to do.
2395 			 */
2396 			goto done;
2397 		}
2398 	}
2399 
2400 	/*
2401 	 * We did not find an entry for the given margin.
2402 	 */
2403 	if (p == NULL) {
2404 		err = ENOENT;
2405 		goto done;
2406 	}
2407 
2408 	ASSERT(p->mmr_ref == 0);
2409 
2410 	/*
2411 	 * Remove it from the list.
2412 	 */
2413 	*pp = p->mmr_nextp;
2414 	kmem_free(p, sizeof (mac_margin_req_t));
2415 done:
2416 	rw_exit(&(mip->mi_data_lock));
2417 	return (err);
2418 }
2419 
2420 /*
2421  * The mac client requests to get the mac's current margin value.
2422  */
2423 void
2424 mac_margin_get(mac_handle_t mh, uint32_t *marginp)
2425 {
2426 	mac_impl_t	*mip = (mac_impl_t *)mh;
2427 
2428 	rw_enter(&(mip->mi_data_lock), RW_READER);
2429 	*marginp = mip->mi_margin;
2430 	rw_exit(&(mip->mi_data_lock));
2431 }
2432 
2433 boolean_t
2434 mac_margin_update(mac_handle_t mh, uint32_t margin)
2435 {
2436 	mac_impl_t	*mip = (mac_impl_t *)mh;
2437 	uint32_t	margin_needed = 0;
2438 
2439 	rw_enter(&(mip->mi_data_lock), RW_WRITER);
2440 
2441 	if (mip->mi_mmrp != NULL)
2442 		margin_needed = mip->mi_mmrp->mmr_margin;
2443 
2444 	if (margin_needed <= margin)
2445 		mip->mi_margin = margin;
2446 
2447 	rw_exit(&(mip->mi_data_lock));
2448 
2449 	if (margin_needed <= margin)
2450 		i_mac_notify(mip, MAC_NOTE_MARGIN);
2451 
2452 	return (margin_needed <= margin);
2453 }
2454 
2455 boolean_t
2456 mac_do_active_set(mac_handle_t mh, boolean_t shareable)
2457 {
2458 	mac_impl_t *mip = (mac_impl_t *)mh;
2459 
2460 	mutex_enter(&mip->mi_activelink_lock);
2461 	if (mip->mi_activelink) {
2462 		mutex_exit(&mip->mi_activelink_lock);
2463 		return (B_FALSE);
2464 	}
2465 	mip->mi_activelink = B_TRUE;
2466 	mip->mi_shareable = shareable;
2467 	mutex_exit(&mip->mi_activelink_lock);
2468 	return (B_TRUE);
2469 }
2470 
2471 /*
2472  * Called by MAC clients. By default, active MAC clients cannot
2473  * share the NIC with VNICs.
2474  */
2475 boolean_t
2476 mac_active_set(mac_handle_t mh)
2477 {
2478 	return (mac_do_active_set(mh, B_FALSE));
2479 }
2480 
2481 /*
2482  * Called by MAC clients which can share the NIC with VNICS, e.g. DLS.
2483  */
2484 boolean_t
2485 mac_active_shareable_set(mac_handle_t mh)
2486 {
2487 	return (mac_do_active_set(mh, B_TRUE));
2488 }
2489 
2490 void
2491 mac_active_clear(mac_handle_t mh)
2492 {
2493 	mac_impl_t *mip = (mac_impl_t *)mh;
2494 
2495 	mutex_enter(&mip->mi_activelink_lock);
2496 	ASSERT(mip->mi_activelink);
2497 	mip->mi_activelink = B_FALSE;
2498 	mutex_exit(&mip->mi_activelink_lock);
2499 }
2500 
2501 boolean_t
2502 mac_vnic_set(mac_handle_t mh, mac_txinfo_t *tx_info, mac_getcapab_t getcapab_fn,
2503     void *getcapab_arg)
2504 {
2505 	mac_impl_t	*mip = (mac_impl_t *)mh;
2506 	mac_vnic_tx_t	*vnic_tx;
2507 
2508 	mutex_enter(&mip->mi_activelink_lock);
2509 	rw_enter(&mip->mi_tx_lock, RW_WRITER);
2510 	ASSERT(!mip->mi_vnic_present);
2511 
2512 	if (mip->mi_activelink && !mip->mi_shareable) {
2513 		/*
2514 		 * The NIC is already used by an active client which cannot
2515 		 * share it with VNICs.
2516 		 */
2517 		rw_exit(&mip->mi_tx_lock);
2518 		mutex_exit(&mip->mi_activelink_lock);
2519 		return (B_FALSE);
2520 	}
2521 
2522 	vnic_tx = kmem_cache_alloc(mac_vnic_tx_cache, KM_SLEEP);
2523 	vnic_tx->mv_refs = 0;
2524 	vnic_tx->mv_txinfo = *tx_info;
2525 	vnic_tx->mv_clearing = B_FALSE;
2526 
2527 	mip->mi_vnic_present = B_TRUE;
2528 	mip->mi_vnic_tx = vnic_tx;
2529 	mip->mi_vnic_getcapab_fn = getcapab_fn;
2530 	mip->mi_vnic_getcapab_arg = getcapab_arg;
2531 	rw_exit(&mip->mi_tx_lock);
2532 	mutex_exit(&mip->mi_activelink_lock);
2533 
2534 	i_mac_notify(mip, MAC_NOTE_VNIC);
2535 	return (B_TRUE);
2536 }
2537 
2538 void
2539 mac_vnic_clear(mac_handle_t mh)
2540 {
2541 	mac_impl_t *mip = (mac_impl_t *)mh;
2542 	mac_vnic_tx_t	*vnic_tx;
2543 
2544 	rw_enter(&mip->mi_tx_lock, RW_WRITER);
2545 	ASSERT(mip->mi_vnic_present);
2546 	mip->mi_vnic_present = B_FALSE;
2547 	/*
2548 	 * Setting mi_vnic_tx to NULL here under the lock guarantees
2549 	 * that no new references to the current VNIC transmit structure
2550 	 * will be taken by mac_vnic_tx(). This is a necessary condition
2551 	 * for safely waiting for the reference count to drop to
2552 	 * zero below.
2553 	 */
2554 	vnic_tx = mip->mi_vnic_tx;
2555 	mip->mi_vnic_tx = NULL;
2556 	mip->mi_vnic_getcapab_fn = NULL;
2557 	mip->mi_vnic_getcapab_arg = NULL;
2558 	rw_exit(&mip->mi_tx_lock);
2559 
2560 	i_mac_notify(mip, MAC_NOTE_VNIC);
2561 
2562 	/*
2563 	 * Wait for all TX calls referencing the VNIC transmit
2564 	 * entry point that was removed to complete.
2565 	 */
2566 	mutex_enter(&vnic_tx->mv_lock);
2567 	vnic_tx->mv_clearing = B_TRUE;
2568 	while (vnic_tx->mv_refs > 0)
2569 		cv_wait(&vnic_tx->mv_cv, &vnic_tx->mv_lock);
2570 	mutex_exit(&vnic_tx->mv_lock);
2571 	kmem_cache_free(mac_vnic_tx_cache, vnic_tx);
2572 }
2573 
2574 /*
2575  * mac_info_get() is used for retrieving the mac_info when a DL_INFO_REQ is
2576  * issued before a DL_ATTACH_REQ. we walk the i_mac_impl_hash table and find
2577  * the first mac_impl_t with a matching driver name; then we copy its mac_info_t
2578  * to the caller. we do all this with i_mac_impl_lock held so the mac_impl_t
2579  * cannot disappear while we are accessing it.
2580  */
2581 typedef struct i_mac_info_state_s {
2582 	const char	*mi_name;
2583 	mac_info_t	*mi_infop;
2584 } i_mac_info_state_t;
2585 
2586 /*ARGSUSED*/
2587 static uint_t
2588 i_mac_info_walker(mod_hash_key_t key, mod_hash_val_t *val, void *arg)
2589 {
2590 	i_mac_info_state_t	*statep = arg;
2591 	mac_impl_t		*mip = (mac_impl_t *)val;
2592 
2593 	if (mip->mi_disabled)
2594 		return (MH_WALK_CONTINUE);
2595 
2596 	if (strcmp(statep->mi_name,
2597 	    ddi_driver_name(mip->mi_dip)) != 0)
2598 		return (MH_WALK_CONTINUE);
2599 
2600 	statep->mi_infop = &mip->mi_info;
2601 	return (MH_WALK_TERMINATE);
2602 }
2603 
2604 boolean_t
2605 mac_info_get(const char *name, mac_info_t *minfop)
2606 {
2607 	i_mac_info_state_t	state;
2608 
2609 	rw_enter(&i_mac_impl_lock, RW_READER);
2610 	state.mi_name = name;
2611 	state.mi_infop = NULL;
2612 	mod_hash_walk(i_mac_impl_hash, i_mac_info_walker, &state);
2613 	if (state.mi_infop == NULL) {
2614 		rw_exit(&i_mac_impl_lock);
2615 		return (B_FALSE);
2616 	}
2617 	*minfop = *state.mi_infop;
2618 	rw_exit(&i_mac_impl_lock);
2619 	return (B_TRUE);
2620 }
2621 
2622 boolean_t
2623 mac_do_capab_get(mac_handle_t mh, mac_capab_t cap, void *cap_data,
2624     boolean_t is_vnic)
2625 {
2626 	mac_impl_t *mip = (mac_impl_t *)mh;
2627 
2628 	if (!is_vnic) {
2629 		rw_enter(&mip->mi_tx_lock, RW_READER);
2630 		if (mip->mi_vnic_present) {
2631 			boolean_t rv;
2632 
2633 			rv = mip->mi_vnic_getcapab_fn(mip->mi_vnic_getcapab_arg,
2634 			    cap, cap_data);
2635 			rw_exit(&mip->mi_tx_lock);
2636 			return (rv);
2637 		}
2638 		rw_exit(&mip->mi_tx_lock);
2639 	}
2640 
2641 	if (mip->mi_callbacks->mc_callbacks & MC_GETCAPAB)
2642 		return (mip->mi_getcapab(mip->mi_driver, cap, cap_data));
2643 	else
2644 		return (B_FALSE);
2645 }
2646 
2647 boolean_t
2648 mac_capab_get(mac_handle_t mh, mac_capab_t cap, void *cap_data)
2649 {
2650 	return (mac_do_capab_get(mh, cap, cap_data, B_FALSE));
2651 }
2652 
2653 boolean_t
2654 mac_vnic_capab_get(mac_handle_t mh, mac_capab_t cap, void *cap_data)
2655 {
2656 	return (mac_do_capab_get(mh, cap, cap_data, B_TRUE));
2657 }
2658 
2659 boolean_t
2660 mac_sap_verify(mac_handle_t mh, uint32_t sap, uint32_t *bind_sap)
2661 {
2662 	mac_impl_t	*mip = (mac_impl_t *)mh;
2663 	return (mip->mi_type->mt_ops.mtops_sap_verify(sap, bind_sap,
2664 	    mip->mi_pdata));
2665 }
2666 
2667 mblk_t *
2668 mac_header(mac_handle_t mh, const uint8_t *daddr, uint32_t sap, mblk_t *payload,
2669     size_t extra_len)
2670 {
2671 	mac_impl_t	*mip = (mac_impl_t *)mh;
2672 	return (mip->mi_type->mt_ops.mtops_header(mip->mi_addr, daddr, sap,
2673 	    mip->mi_pdata, payload, extra_len));
2674 }
2675 
2676 int
2677 mac_header_info(mac_handle_t mh, mblk_t *mp, mac_header_info_t *mhip)
2678 {
2679 	mac_impl_t	*mip = (mac_impl_t *)mh;
2680 	return (mip->mi_type->mt_ops.mtops_header_info(mp, mip->mi_pdata,
2681 	    mhip));
2682 }
2683 
2684 mblk_t *
2685 mac_header_cook(mac_handle_t mh, mblk_t *mp)
2686 {
2687 	mac_impl_t	*mip = (mac_impl_t *)mh;
2688 	if (mip->mi_type->mt_ops.mtops_ops & MTOPS_HEADER_COOK) {
2689 		if (DB_REF(mp) > 1) {
2690 			mblk_t *newmp = copymsg(mp);
2691 			if (newmp == NULL)
2692 				return (NULL);
2693 			freemsg(mp);
2694 			mp = newmp;
2695 		}
2696 		return (mip->mi_type->mt_ops.mtops_header_cook(mp,
2697 		    mip->mi_pdata));
2698 	}
2699 	return (mp);
2700 }
2701 
2702 mblk_t *
2703 mac_header_uncook(mac_handle_t mh, mblk_t *mp)
2704 {
2705 	mac_impl_t	*mip = (mac_impl_t *)mh;
2706 	if (mip->mi_type->mt_ops.mtops_ops & MTOPS_HEADER_UNCOOK) {
2707 		if (DB_REF(mp) > 1) {
2708 			mblk_t *newmp = copymsg(mp);
2709 			if (newmp == NULL)
2710 				return (NULL);
2711 			freemsg(mp);
2712 			mp = newmp;
2713 		}
2714 		return (mip->mi_type->mt_ops.mtops_header_uncook(mp,
2715 		    mip->mi_pdata));
2716 	}
2717 	return (mp);
2718 }
2719 
2720 void
2721 mac_init_ops(struct dev_ops *ops, const char *name)
2722 {
2723 	dld_init_ops(ops, name);
2724 }
2725 
2726 void
2727 mac_fini_ops(struct dev_ops *ops)
2728 {
2729 	dld_fini_ops(ops);
2730 }
2731 
2732 /*
2733  * MAC Type Plugin functions.
2734  */
2735 
2736 mactype_register_t *
2737 mactype_alloc(uint_t mactype_version)
2738 {
2739 	mactype_register_t *mtrp;
2740 
2741 	/*
2742 	 * Make sure there isn't a version mismatch between the plugin and
2743 	 * the framework.  In the future, if multiple versions are
2744 	 * supported, this check could become more sophisticated.
2745 	 */
2746 	if (mactype_version != MACTYPE_VERSION)
2747 		return (NULL);
2748 
2749 	mtrp = kmem_zalloc(sizeof (mactype_register_t), KM_SLEEP);
2750 	mtrp->mtr_version = mactype_version;
2751 	return (mtrp);
2752 }
2753 
2754 void
2755 mactype_free(mactype_register_t *mtrp)
2756 {
2757 	kmem_free(mtrp, sizeof (mactype_register_t));
2758 }
2759 
2760 int
2761 mactype_register(mactype_register_t *mtrp)
2762 {
2763 	mactype_t	*mtp;
2764 	mactype_ops_t	*ops = mtrp->mtr_ops;
2765 
2766 	/* Do some sanity checking before we register this MAC type. */
2767 	if (mtrp->mtr_ident == NULL || ops == NULL || mtrp->mtr_addrlen == 0)
2768 		return (EINVAL);
2769 
2770 	/*
2771 	 * Verify that all mandatory callbacks are set in the ops
2772 	 * vector.
2773 	 */
2774 	if (ops->mtops_unicst_verify == NULL ||
2775 	    ops->mtops_multicst_verify == NULL ||
2776 	    ops->mtops_sap_verify == NULL ||
2777 	    ops->mtops_header == NULL ||
2778 	    ops->mtops_header_info == NULL) {
2779 		return (EINVAL);
2780 	}
2781 
2782 	mtp = kmem_zalloc(sizeof (*mtp), KM_SLEEP);
2783 	mtp->mt_ident = mtrp->mtr_ident;
2784 	mtp->mt_ops = *ops;
2785 	mtp->mt_type = mtrp->mtr_mactype;
2786 	mtp->mt_nativetype = mtrp->mtr_nativetype;
2787 	mtp->mt_addr_length = mtrp->mtr_addrlen;
2788 	if (mtrp->mtr_brdcst_addr != NULL) {
2789 		mtp->mt_brdcst_addr = kmem_alloc(mtrp->mtr_addrlen, KM_SLEEP);
2790 		bcopy(mtrp->mtr_brdcst_addr, mtp->mt_brdcst_addr,
2791 		    mtrp->mtr_addrlen);
2792 	}
2793 
2794 	mtp->mt_stats = mtrp->mtr_stats;
2795 	mtp->mt_statcount = mtrp->mtr_statcount;
2796 
2797 	if (mod_hash_insert(i_mactype_hash,
2798 	    (mod_hash_key_t)mtp->mt_ident, (mod_hash_val_t)mtp) != 0) {
2799 		kmem_free(mtp->mt_brdcst_addr, mtp->mt_addr_length);
2800 		kmem_free(mtp, sizeof (*mtp));
2801 		return (EEXIST);
2802 	}
2803 	return (0);
2804 }
2805 
2806 int
2807 mactype_unregister(const char *ident)
2808 {
2809 	mactype_t	*mtp;
2810 	mod_hash_val_t	val;
2811 	int 		err;
2812 
2813 	/*
2814 	 * Let's not allow MAC drivers to use this plugin while we're
2815 	 * trying to unregister it.  Holding i_mactype_lock also prevents a
2816 	 * plugin from unregistering while a MAC driver is attempting to
2817 	 * hold a reference to it in i_mactype_getplugin().
2818 	 */
2819 	mutex_enter(&i_mactype_lock);
2820 
2821 	if ((err = mod_hash_find(i_mactype_hash, (mod_hash_key_t)ident,
2822 	    (mod_hash_val_t *)&mtp)) != 0) {
2823 		/* A plugin is trying to unregister, but it never registered. */
2824 		err = ENXIO;
2825 		goto done;
2826 	}
2827 
2828 	if (mtp->mt_ref != 0) {
2829 		err = EBUSY;
2830 		goto done;
2831 	}
2832 
2833 	err = mod_hash_remove(i_mactype_hash, (mod_hash_key_t)ident, &val);
2834 	ASSERT(err == 0);
2835 	if (err != 0) {
2836 		/* This should never happen, thus the ASSERT() above. */
2837 		err = EINVAL;
2838 		goto done;
2839 	}
2840 	ASSERT(mtp == (mactype_t *)val);
2841 
2842 	kmem_free(mtp->mt_brdcst_addr, mtp->mt_addr_length);
2843 	kmem_free(mtp, sizeof (mactype_t));
2844 done:
2845 	mutex_exit(&i_mactype_lock);
2846 	return (err);
2847 }
2848 
2849 int
2850 mac_set_prop(mac_handle_t mh, mac_prop_t *macprop, void *val, uint_t valsize)
2851 {
2852 	int err = ENOTSUP;
2853 	mac_impl_t *mip = (mac_impl_t *)mh;
2854 
2855 	if (mip->mi_callbacks->mc_callbacks & MC_SETPROP) {
2856 		err = mip->mi_callbacks->mc_setprop(mip->mi_driver,
2857 		    macprop->mp_name, macprop->mp_id, valsize, val);
2858 	}
2859 	return (err);
2860 }
2861 
2862 int
2863 mac_get_prop(mac_handle_t mh, mac_prop_t *macprop, void *val, uint_t valsize)
2864 {
2865 	int err = ENOTSUP;
2866 	mac_impl_t *mip = (mac_impl_t *)mh;
2867 
2868 	if (mip->mi_callbacks->mc_callbacks & MC_GETPROP) {
2869 		err = mip->mi_callbacks->mc_getprop(mip->mi_driver,
2870 		    macprop->mp_name, macprop->mp_id, valsize, val);
2871 	}
2872 	return (err);
2873 }
2874 
2875 int
2876 mac_maxsdu_update(mac_handle_t mh, uint_t sdu_max)
2877 {
2878 	mac_impl_t	*mip = (mac_impl_t *)mh;
2879 
2880 	if (sdu_max <= mip->mi_sdu_min)
2881 		return (EINVAL);
2882 	mip->mi_sdu_max = sdu_max;
2883 
2884 	/* Send a MAC_NOTE_SDU_SIZE notification. */
2885 	i_mac_notify(mip, MAC_NOTE_SDU_SIZE);
2886 	return (0);
2887 }
2888