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