xref: /illumos-gate/usr/src/uts/common/io/mac/mac.c (revision 88f3d7297a011d0fa0768a7b2082305a822487b2)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 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/stat.h>
36 #include <sys/stream.h>
37 #include <sys/strsun.h>
38 #include <sys/strsubr.h>
39 #include <sys/dlpi.h>
40 #include <sys/mac.h>
41 #include <sys/mac_impl.h>
42 #include <sys/dld_impl.h>
43 
44 #define	IMPL_HASHSZ	67	/* prime */
45 
46 static kmem_cache_t	*i_mac_impl_cachep;
47 static ght_t		i_mac_impl_hash;
48 
49 /*
50  * Private functions.
51  */
52 
53 /*ARGSUSED*/
54 static boolean_t
55 i_mac_ether_unicst_verify(mac_impl_t *mip, const uint8_t *addr)
56 {
57 	/*
58 	 * Check the address is not a group address.
59 	 */
60 	if (addr[0] & 0x01)
61 		return (B_FALSE);
62 
63 	return (B_TRUE);
64 }
65 
66 static boolean_t
67 i_mac_ether_multicst_verify(mac_impl_t *mip, const uint8_t *addr)
68 {
69 	mac_t		*mp = mip->mi_mp;
70 
71 	/*
72 	 * Check the address is a group address.
73 	 */
74 	if (!(addr[0] & 0x01))
75 		return (B_FALSE);
76 
77 	/*
78 	 * Check the address is not the media broadcast address.
79 	 */
80 	if (bcmp(addr, mp->m_info.mi_brdcst_addr, mip->mi_addr_length) == 0)
81 		return (B_FALSE);
82 
83 	return (B_TRUE);
84 }
85 
86 /*ARGSUSED*/
87 static int
88 i_mac_constructor(void *buf, void *arg, int kmflag)
89 {
90 	mac_impl_t	*mip = buf;
91 
92 	bzero(buf, sizeof (mac_impl_t));
93 
94 	mip->mi_link = LINK_STATE_UNKNOWN;
95 
96 	rw_init(&mip->mi_state_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_txloop_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 	return (0);
104 }
105 
106 /*ARGSUSED*/
107 static void
108 i_mac_destructor(void *buf, void *arg)
109 {
110 	mac_impl_t	*mip = buf;
111 
112 	ASSERT(mip->mi_mp == NULL);
113 	ASSERT(mip->mi_hte == NULL);
114 	ASSERT(mip->mi_ref == 0);
115 	ASSERT(mip->mi_active == 0);
116 	ASSERT(mip->mi_link == LINK_STATE_UNKNOWN);
117 	ASSERT(mip->mi_devpromisc == 0);
118 	ASSERT(mip->mi_promisc == 0);
119 	ASSERT(mip->mi_mmap == NULL);
120 	ASSERT(mip->mi_mnfp == NULL);
121 	ASSERT(mip->mi_resource_add == NULL);
122 	ASSERT(mip->mi_ksp == NULL);
123 
124 	rw_destroy(&mip->mi_state_lock);
125 	rw_destroy(&mip->mi_data_lock);
126 	rw_destroy(&mip->mi_notify_lock);
127 	rw_destroy(&mip->mi_rx_lock);
128 	rw_destroy(&mip->mi_txloop_lock);
129 	rw_destroy(&mip->mi_resource_lock);
130 	mutex_destroy(&mip->mi_activelink_lock);
131 }
132 
133 int
134 i_mac_create(mac_t *mp)
135 {
136 	dev_info_t	*dip;
137 	mac_impl_t	*mip;
138 	int		err;
139 	ghte_t		hte;
140 
141 	dip = mp->m_dip;
142 	ASSERT(dip != NULL);
143 	ASSERT(ddi_get_instance(dip) >= 0);
144 
145 	/*
146 	 * Allocate a new mac_impl_t.
147 	 */
148 	mip = kmem_cache_alloc(i_mac_impl_cachep, KM_SLEEP);
149 
150 	/*
151 	 * Construct a name.
152 	 */
153 	(void) snprintf(mip->mi_dev, MAXNAMELEN - 1, "%s%d",
154 	    ddi_driver_name(dip), ddi_get_instance(dip));
155 	mip->mi_port = mp->m_port;
156 
157 	MAC_NAME(mip->mi_name, mip->mi_dev, mip->mi_port);
158 
159 	/*
160 	 * Set the mac_t/mac_impl_t cross-references.
161 	 */
162 	mip->mi_mp = mp;
163 	mp->m_impl = (void *)mip;
164 
165 	/*
166 	 * Allocate a hash table entry.
167 	 */
168 	hte = ght_alloc(i_mac_impl_hash, KM_SLEEP);
169 
170 	GHT_KEY(hte) = GHT_PTR_TO_KEY(mip->mi_name);
171 	GHT_VAL(hte) = GHT_PTR_TO_VAL(mip);
172 
173 	/*
174 	 * Insert the hash table entry.
175 	 */
176 	ght_lock(i_mac_impl_hash, GHT_WRITE);
177 	if ((err = ght_insert(hte)) != 0) {
178 		ght_free(hte);
179 		kmem_cache_free(i_mac_impl_cachep, mip);
180 		goto done;
181 	}
182 
183 	mip->mi_hte = hte;
184 
185 	/*
186 	 * Copy the fixed 'factory' MAC address from the immutable info.
187 	 * This is taken to be the MAC address currently in use.
188 	 */
189 	mip->mi_addr_length = mp->m_info.mi_addr_length;
190 	bcopy(mp->m_info.mi_unicst_addr, mip->mi_addr, mip->mi_addr_length);
191 
192 	/*
193 	 * Set up the address verification functions.
194 	 */
195 	ASSERT(mp->m_info.mi_media == DL_ETHER);
196 	mip->mi_unicst_verify = i_mac_ether_unicst_verify;
197 	mip->mi_multicst_verify = i_mac_ether_multicst_verify;
198 
199 	/*
200 	 * Set up the two possible transmit routines.
201 	 */
202 	mip->mi_txinfo.mt_fn = mp->m_tx;
203 	mip->mi_txinfo.mt_arg = mp->m_driver;
204 	mip->mi_txloopinfo.mt_fn = mac_txloop;
205 	mip->mi_txloopinfo.mt_arg = mip;
206 
207 	/*
208 	 * Initialize the kstats for this device.
209 	 */
210 	mac_stat_create(mip);
211 
212 done:
213 	ght_unlock(i_mac_impl_hash);
214 	return (err);
215 }
216 
217 static void
218 i_mac_destroy(mac_t *mp)
219 {
220 	mac_impl_t		*mip = mp->m_impl;
221 	ghte_t			hte;
222 	mac_multicst_addr_t	*p, *nextp;
223 
224 	ght_lock(i_mac_impl_hash, GHT_WRITE);
225 
226 	ASSERT(mip->mi_ref == 0);
227 	ASSERT(!mip->mi_activelink);
228 
229 	/*
230 	 * Destroy the kstats.
231 	 */
232 	mac_stat_destroy(mip);
233 
234 	/*
235 	 * Remove and destroy the hash table entry.
236 	 */
237 	hte = mip->mi_hte;
238 	ght_remove(hte);
239 	ght_free(hte);
240 	mip->mi_hte = NULL;
241 
242 	/*
243 	 * Free the list of multicast addresses.
244 	 */
245 	for (p = mip->mi_mmap; p != NULL; p = nextp) {
246 		nextp = p->mma_nextp;
247 		kmem_free(p, sizeof (mac_multicst_addr_t));
248 	}
249 	mip->mi_mmap = NULL;
250 
251 	/*
252 	 * Clean up the mac_impl_t ready to go back into the cache.
253 	 */
254 	mp->m_impl = NULL;
255 	mip->mi_mp = NULL;
256 	mip->mi_link = LINK_STATE_UNKNOWN;
257 	mip->mi_destroying = B_FALSE;
258 
259 	/*
260 	 * Free the structure back to the cache.
261 	 */
262 	kmem_cache_free(i_mac_impl_cachep, mip);
263 
264 	ght_unlock(i_mac_impl_hash);
265 }
266 
267 static void
268 i_mac_notify(mac_impl_t *mip, mac_notify_type_t type)
269 {
270 	mac_notify_fn_t		*mnfp;
271 	mac_notify_t		notify;
272 	void			*arg;
273 
274 	/*
275 	 * Walk the list of notifications.
276 	 */
277 	rw_enter(&(mip->mi_notify_lock), RW_READER);
278 	for (mnfp = mip->mi_mnfp; mnfp != NULL; mnfp = mnfp->mnf_nextp) {
279 		notify = mnfp->mnf_fn;
280 		arg = mnfp->mnf_arg;
281 
282 		ASSERT(notify != NULL);
283 		notify(arg, type);
284 	}
285 	rw_exit(&(mip->mi_notify_lock));
286 }
287 
288 /*
289  * Module initialization functions.
290  */
291 
292 void
293 mac_init(void)
294 {
295 	int	err;
296 
297 	i_mac_impl_cachep = kmem_cache_create("mac_impl_cache",
298 	    sizeof (mac_impl_t), 0, i_mac_constructor, i_mac_destructor, NULL,
299 	    NULL, NULL, 0);
300 	ASSERT(i_mac_impl_cachep != NULL);
301 
302 	err = ght_str_create("mac_impl_hash", IMPL_HASHSZ, &i_mac_impl_hash);
303 	ASSERT(err == 0);
304 }
305 
306 int
307 mac_fini(void)
308 {
309 	int	err;
310 
311 	if ((err = ght_destroy(i_mac_impl_hash)) != 0)
312 		return (err);
313 
314 	kmem_cache_destroy(i_mac_impl_cachep);
315 	return (0);
316 }
317 
318 /*
319  * Client functions.
320  */
321 
322 int
323 mac_open(const char *dev, uint_t port, mac_handle_t *mhp)
324 {
325 	char		name[MAXNAMELEN];
326 	char		driver[MAXNAMELEN];
327 	uint_t		instance;
328 	major_t		major;
329 	dev_info_t	*dip;
330 	mac_impl_t	*mip;
331 	ghte_t		hte;
332 	int		err;
333 
334 	/*
335 	 * Check the device name length to make sure it won't overflow our
336 	 * buffer.
337 	 */
338 	if (strlen(dev) >= MAXNAMELEN)
339 		return (EINVAL);
340 
341 	/*
342 	 * Split the device name into driver and instance components.
343 	 */
344 	if (ddi_parse(dev, driver, &instance) != DDI_SUCCESS)
345 		return (EINVAL);
346 
347 	/*
348 	 * Get the major number of the driver.
349 	 */
350 	if ((major = ddi_name_to_major(driver)) == (major_t)-1)
351 		return (EINVAL);
352 
353 	/*
354 	 * Hold the given instance to prevent it from being detached.
355 	 * (This will also attach it if it is not currently attached).
356 	 */
357 	if ((dip = ddi_hold_devi_by_instance(major, instance, 0)) == NULL)
358 		return (EINVAL);
359 
360 	/*
361 	 * Construct the name of the MAC interface.
362 	 */
363 	MAC_NAME(name, dev, port);
364 
365 	/*
366 	 * Look up its entry in the global hash table.
367 	 */
368 again:
369 	ght_lock(i_mac_impl_hash, GHT_WRITE);
370 	if ((err = ght_find(i_mac_impl_hash, GHT_PTR_TO_KEY(name), &hte)) != 0)
371 		goto failed;
372 
373 	mip = (mac_impl_t *)GHT_VAL(hte);
374 	ASSERT(mip->mi_mp->m_dip == dip);
375 
376 	if (mip->mi_destroying) {
377 		ght_unlock(i_mac_impl_hash);
378 		goto again;
379 	}
380 
381 	mip->mi_ref++;
382 	ght_unlock(i_mac_impl_hash);
383 
384 	*mhp = (mac_handle_t)mip;
385 	return (0);
386 
387 failed:
388 	ght_unlock(i_mac_impl_hash);
389 	ddi_release_devi(dip);
390 	return (err);
391 }
392 
393 void
394 mac_close(mac_handle_t mh)
395 {
396 	mac_impl_t	*mip = (mac_impl_t *)mh;
397 	dev_info_t	*dip = mip->mi_mp->m_dip;
398 
399 	ght_lock(i_mac_impl_hash, GHT_WRITE);
400 
401 	ASSERT(mip->mi_ref != 0);
402 	if (--mip->mi_ref == 0) {
403 		ASSERT(!mip->mi_activelink);
404 	}
405 	ddi_release_devi(dip);
406 	ght_unlock(i_mac_impl_hash);
407 }
408 
409 const mac_info_t *
410 mac_info(mac_handle_t mh)
411 {
412 	mac_impl_t	*mip = (mac_impl_t *)mh;
413 	mac_t		*mp = mip->mi_mp;
414 
415 	/*
416 	 * Return a pointer to the mac_info_t embedded in the mac_t.
417 	 */
418 	return (&(mp->m_info));
419 }
420 
421 uint64_t
422 mac_stat_get(mac_handle_t mh, enum mac_stat stat)
423 {
424 	mac_impl_t	*mip = (mac_impl_t *)mh;
425 	mac_t		*mp = mip->mi_mp;
426 
427 	ASSERT(mp->m_info.mi_stat[stat]);
428 	ASSERT(mp->m_stat != NULL);
429 
430 	/*
431 	 * Call the driver to get the given statistic.
432 	 */
433 	return (mp->m_stat(mp->m_driver, stat));
434 }
435 
436 int
437 mac_start(mac_handle_t mh)
438 {
439 	mac_impl_t	*mip = (mac_impl_t *)mh;
440 	mac_t		*mp = mip->mi_mp;
441 	int		err;
442 
443 	ASSERT(mp->m_start != NULL);
444 
445 	rw_enter(&(mip->mi_state_lock), RW_WRITER);
446 
447 	/*
448 	 * Check whether the device is already started.
449 	 */
450 	if (mip->mi_active++ != 0) {
451 		/*
452 		 * It's already started so there's nothing more to do.
453 		 */
454 		err = 0;
455 		goto done;
456 	}
457 
458 	/*
459 	 * Start the device.
460 	 */
461 	if ((err = mp->m_start(mp->m_driver)) != 0)
462 		--mip->mi_active;
463 
464 done:
465 	rw_exit(&(mip->mi_state_lock));
466 	return (err);
467 }
468 
469 void
470 mac_stop(mac_handle_t mh)
471 {
472 	mac_impl_t	*mip = (mac_impl_t *)mh;
473 	mac_t		*mp = mip->mi_mp;
474 
475 	ASSERT(mp->m_stop != NULL);
476 
477 	rw_enter(&(mip->mi_state_lock), RW_WRITER);
478 
479 	/*
480 	 * Check whether the device is still needed.
481 	 */
482 	ASSERT(mip->mi_active != 0);
483 	if (--mip->mi_active != 0) {
484 		/*
485 		 * It's still needed so there's nothing more to do.
486 		 */
487 		goto done;
488 	}
489 
490 	/*
491 	 * Stop the device.
492 	 */
493 	mp->m_stop(mp->m_driver);
494 
495 done:
496 	rw_exit(&(mip->mi_state_lock));
497 }
498 
499 int
500 mac_multicst_add(mac_handle_t mh, const uint8_t *addr)
501 {
502 	mac_impl_t		*mip = (mac_impl_t *)mh;
503 	mac_t			*mp = mip->mi_mp;
504 	mac_multicst_addr_t	**pp;
505 	mac_multicst_addr_t	*p;
506 	int			err;
507 
508 	ASSERT(mp->m_multicst != NULL);
509 
510 	/*
511 	 * Verify the address.
512 	 */
513 	if (!(mip->mi_multicst_verify(mip, addr)))
514 		return (EINVAL);
515 
516 	/*
517 	 * Check whether the given address is already enabled.
518 	 */
519 	rw_enter(&(mip->mi_data_lock), RW_WRITER);
520 	for (pp = &(mip->mi_mmap); (p = *pp) != NULL; pp = &(p->mma_nextp)) {
521 		if (bcmp(p->mma_addr, addr, mip->mi_addr_length) == 0) {
522 			/*
523 			 * The address is already enabled so just bump the
524 			 * reference count.
525 			 */
526 			p->mma_ref++;
527 			err = 0;
528 			goto done;
529 		}
530 	}
531 
532 	/*
533 	 * Allocate a new list entry.
534 	 */
535 	if ((p = kmem_zalloc(sizeof (mac_multicst_addr_t),
536 	    KM_NOSLEEP)) == NULL) {
537 		err = ENOMEM;
538 		goto done;
539 	}
540 
541 	/*
542 	 * Enable a new multicast address.
543 	 */
544 	if ((err = mp->m_multicst(mp->m_driver, B_TRUE, addr)) != 0) {
545 		kmem_free(p, sizeof (mac_multicst_addr_t));
546 		goto done;
547 	}
548 
549 	/*
550 	 * Add the address to the list of enabled addresses.
551 	 */
552 	bcopy(addr, p->mma_addr, mip->mi_addr_length);
553 	p->mma_ref++;
554 	*pp = p;
555 
556 done:
557 	rw_exit(&(mip->mi_data_lock));
558 	return (err);
559 }
560 
561 int
562 mac_multicst_remove(mac_handle_t mh, const uint8_t *addr)
563 {
564 	mac_impl_t		*mip = (mac_impl_t *)mh;
565 	mac_t			*mp = mip->mi_mp;
566 	mac_multicst_addr_t	**pp;
567 	mac_multicst_addr_t	*p;
568 	int			err;
569 
570 	ASSERT(mp->m_multicst != NULL);
571 
572 	/*
573 	 * Find the entry in the list for the given address.
574 	 */
575 	rw_enter(&(mip->mi_data_lock), RW_WRITER);
576 	for (pp = &(mip->mi_mmap); (p = *pp) != NULL; pp = &(p->mma_nextp)) {
577 		if (bcmp(p->mma_addr, addr, mip->mi_addr_length) == 0) {
578 			if (--p->mma_ref == 0)
579 				break;
580 
581 			/*
582 			 * There is still a reference to this address so
583 			 * there's nothing more to do.
584 			 */
585 			err = 0;
586 			goto done;
587 		}
588 	}
589 
590 	/*
591 	 * We did not find an entry for the given address so it is not
592 	 * currently enabled.
593 	 */
594 	if (p == NULL) {
595 		err = ENOENT;
596 		goto done;
597 	}
598 	ASSERT(p->mma_ref == 0);
599 
600 	/*
601 	 * Disable the multicast address.
602 	 */
603 	if ((err = mp->m_multicst(mp->m_driver, B_FALSE, addr)) != 0) {
604 		p->mma_ref++;
605 		goto done;
606 	}
607 
608 	/*
609 	 * Remove it from the list.
610 	 */
611 	*pp = p->mma_nextp;
612 	kmem_free(p, sizeof (mac_multicst_addr_t));
613 
614 done:
615 	rw_exit(&(mip->mi_data_lock));
616 	return (err);
617 }
618 
619 int
620 mac_unicst_set(mac_handle_t mh, const uint8_t *addr)
621 {
622 	mac_impl_t	*mip = (mac_impl_t *)mh;
623 	mac_t		*mp = mip->mi_mp;
624 	int		err;
625 	boolean_t	notify = B_FALSE;
626 
627 	ASSERT(mp->m_unicst != NULL);
628 
629 	/*
630 	 * Verify the address.
631 	 */
632 	if (!(mip->mi_unicst_verify(mip, addr)))
633 		return (EINVAL);
634 
635 	/*
636 	 * Program the new unicast address.
637 	 */
638 	rw_enter(&(mip->mi_data_lock), RW_WRITER);
639 
640 	/*
641 	 * If address doesn't change, do nothing.
642 	 * This check is necessary otherwise it may call into mac_unicst_set
643 	 * recursively.
644 	 */
645 	if (bcmp(addr, mip->mi_addr, mip->mi_addr_length) == 0) {
646 		err = 0;
647 		goto done;
648 	}
649 
650 	if ((err = mp->m_unicst(mp->m_driver, addr)) != 0)
651 		goto done;
652 
653 	/*
654 	 * Save the address and flag that we need to send a notification.
655 	 */
656 	bcopy(addr, mip->mi_addr, mip->mi_addr_length);
657 	notify = B_TRUE;
658 
659 done:
660 	rw_exit(&(mip->mi_data_lock));
661 
662 	if (notify)
663 		i_mac_notify(mip, MAC_NOTE_UNICST);
664 
665 	return (err);
666 }
667 
668 void
669 mac_unicst_get(mac_handle_t mh, uint8_t *addr)
670 {
671 	mac_impl_t	*mip = (mac_impl_t *)mh;
672 
673 	/*
674 	 * Copy out the current unicast address.
675 	 */
676 	rw_enter(&(mip->mi_data_lock), RW_READER);
677 	bcopy(mip->mi_addr, addr, mip->mi_addr_length);
678 	rw_exit(&(mip->mi_data_lock));
679 }
680 
681 int
682 mac_promisc_set(mac_handle_t mh, boolean_t on, mac_promisc_type_t ptype)
683 {
684 	mac_impl_t	*mip = (mac_impl_t *)mh;
685 	mac_t		*mp = mip->mi_mp;
686 	int		err = 0;
687 
688 	ASSERT(mp->m_promisc != NULL);
689 	ASSERT(ptype == MAC_DEVPROMISC || ptype == MAC_PROMISC);
690 
691 	/*
692 	 * Determine whether we should enable or disable promiscuous mode.
693 	 * For details on the distinction between "device promiscuous mode"
694 	 * and "MAC promiscuous mode", see PSARC/2005/289.
695 	 */
696 	rw_enter(&(mip->mi_data_lock), RW_WRITER);
697 	if (on) {
698 		/*
699 		 * Enable promiscuous mode on the device if not yet enabled.
700 		 */
701 		if (mip->mi_devpromisc++ == 0) {
702 			if ((err = mp->m_promisc(mp->m_driver, B_TRUE)) != 0) {
703 				mip->mi_devpromisc--;
704 				goto done;
705 			}
706 			i_mac_notify(mip, MAC_NOTE_DEVPROMISC);
707 		}
708 
709 		/*
710 		 * Enable promiscuous mode on the MAC if not yet enabled.
711 		 */
712 		if (ptype == MAC_PROMISC && mip->mi_promisc++ == 0)
713 			i_mac_notify(mip, MAC_NOTE_PROMISC);
714 	} else {
715 		if (mip->mi_devpromisc == 0) {
716 			err = EPROTO;
717 			goto done;
718 		}
719 
720 		/*
721 		 * Disable promiscuous mode on the device if this is the last
722 		 * enabling.
723 		 */
724 		if (--mip->mi_devpromisc == 0) {
725 			if ((err = mp->m_promisc(mp->m_driver, B_FALSE)) != 0) {
726 				mip->mi_devpromisc++;
727 				goto done;
728 			}
729 			i_mac_notify(mip, MAC_NOTE_DEVPROMISC);
730 		}
731 
732 		/*
733 		 * Disable promiscuous mode on the MAC if this is the last
734 		 * enabling.
735 		 */
736 		if (ptype == MAC_PROMISC && --mip->mi_promisc == 0)
737 			i_mac_notify(mip, MAC_NOTE_PROMISC);
738 	}
739 
740 done:
741 	rw_exit(&(mip->mi_data_lock));
742 	return (err);
743 }
744 
745 boolean_t
746 mac_promisc_get(mac_handle_t mh, mac_promisc_type_t ptype)
747 {
748 	mac_impl_t		*mip = (mac_impl_t *)mh;
749 
750 	ASSERT(ptype == MAC_DEVPROMISC || ptype == MAC_PROMISC);
751 
752 	/*
753 	 * Return the current promiscuity.
754 	 */
755 	if (ptype == MAC_DEVPROMISC)
756 		return (mip->mi_devpromisc != 0);
757 	else
758 		return (mip->mi_promisc != 0);
759 }
760 
761 void
762 mac_resources(mac_handle_t mh)
763 {
764 	mac_impl_t	*mip = (mac_impl_t *)mh;
765 	mac_t		*mp = mip->mi_mp;
766 
767 	ASSERT(mp->m_resources != NULL);
768 
769 	/*
770 	 * Call the driver to register its resources.
771 	 */
772 	mp->m_resources(mp->m_driver);
773 }
774 
775 void
776 mac_ioctl(mac_handle_t mh, queue_t *wq, mblk_t *bp)
777 {
778 	mac_impl_t	*mip = (mac_impl_t *)mh;
779 	mac_t		*mp = mip->mi_mp;
780 
781 	ASSERT(mp->m_ioctl != NULL);
782 
783 	/*
784 	 * Call the driver to handle the ioctl.
785 	 */
786 	mp->m_ioctl(mp->m_driver, wq, bp);
787 }
788 
789 const mac_txinfo_t *
790 mac_tx_get(mac_handle_t mh)
791 {
792 	mac_impl_t	*mip = (mac_impl_t *)mh;
793 	mac_txinfo_t	*mtp;
794 
795 	/*
796 	 * Grab the lock to prevent us from racing with MAC_PROMISC being
797 	 * changed.  This is sufficient since MAC clients are careful to always
798 	 * call mac_txloop_add() prior to enabling MAC_PROMISC, and to disable
799 	 * MAC_PROMISC prior to calling mac_txloop_remove().
800 	 */
801 	rw_enter(&mip->mi_txloop_lock, RW_READER);
802 
803 	if (mac_promisc_get(mh, MAC_PROMISC)) {
804 		ASSERT(mip->mi_mtfp != NULL);
805 		mtp = &mip->mi_txloopinfo;
806 	} else {
807 		/*
808 		 * Note that we cannot ASSERT() that mip->mi_mtfp is NULL,
809 		 * because to satisfy the above ASSERT(), we have to disable
810 		 * MAC_PROMISC prior to calling mac_txloop_remove().
811 		 */
812 		mtp = &mip->mi_txinfo;
813 
814 	}
815 
816 	rw_exit(&mip->mi_txloop_lock);
817 	return (mtp);
818 }
819 
820 link_state_t
821 mac_link_get(mac_handle_t mh)
822 {
823 	mac_impl_t	*mip = (mac_impl_t *)mh;
824 
825 	/*
826 	 * Return the current link state.
827 	 */
828 	return (mip->mi_link);
829 }
830 
831 mac_notify_handle_t
832 mac_notify_add(mac_handle_t mh, mac_notify_t notify, void *arg)
833 {
834 	mac_impl_t		*mip = (mac_impl_t *)mh;
835 	mac_notify_fn_t		*mnfp;
836 
837 	mnfp = kmem_zalloc(sizeof (mac_notify_fn_t), KM_SLEEP);
838 	mnfp->mnf_fn = notify;
839 	mnfp->mnf_arg = arg;
840 
841 	/*
842 	 * Add it to the head of the 'notify' callback list.
843 	 */
844 	rw_enter(&(mip->mi_notify_lock), RW_WRITER);
845 	mnfp->mnf_nextp = mip->mi_mnfp;
846 	mip->mi_mnfp = mnfp;
847 	rw_exit(&(mip->mi_notify_lock));
848 
849 	return ((mac_notify_handle_t)mnfp);
850 }
851 
852 void
853 mac_notify_remove(mac_handle_t mh, mac_notify_handle_t mnh)
854 {
855 	mac_impl_t		*mip = (mac_impl_t *)mh;
856 	mac_notify_fn_t		*mnfp = (mac_notify_fn_t *)mnh;
857 	mac_notify_fn_t		**pp;
858 	mac_notify_fn_t		*p;
859 
860 	/*
861 	 * Search the 'notify' callback list for the function closure.
862 	 */
863 	rw_enter(&(mip->mi_notify_lock), RW_WRITER);
864 	for (pp = &(mip->mi_mnfp); (p = *pp) != NULL;
865 	    pp = &(p->mnf_nextp)) {
866 		if (p == mnfp)
867 			break;
868 	}
869 	ASSERT(p != NULL);
870 
871 	/*
872 	 * Remove it from the list.
873 	 */
874 	*pp = p->mnf_nextp;
875 	rw_exit(&(mip->mi_notify_lock));
876 
877 	/*
878 	 * Free it.
879 	 */
880 	kmem_free(mnfp, sizeof (mac_notify_fn_t));
881 }
882 
883 void
884 mac_notify(mac_handle_t mh)
885 {
886 	mac_impl_t		*mip = (mac_impl_t *)mh;
887 	mac_notify_type_t	type;
888 
889 	for (type = 0; type < MAC_NNOTE; type++)
890 		i_mac_notify(mip, type);
891 }
892 
893 mac_rx_handle_t
894 mac_rx_add(mac_handle_t mh, mac_rx_t rx, void *arg)
895 {
896 	mac_impl_t	*mip = (mac_impl_t *)mh;
897 	mac_rx_fn_t	*mrfp;
898 
899 	mrfp = kmem_zalloc(sizeof (mac_rx_fn_t), KM_SLEEP);
900 	mrfp->mrf_fn = rx;
901 	mrfp->mrf_arg = arg;
902 
903 	/*
904 	 * Add it to the head of the 'rx' callback list.
905 	 */
906 	rw_enter(&(mip->mi_rx_lock), RW_WRITER);
907 	mrfp->mrf_nextp = mip->mi_mrfp;
908 	mip->mi_mrfp = mrfp;
909 	rw_exit(&(mip->mi_rx_lock));
910 
911 	return ((mac_rx_handle_t)mrfp);
912 }
913 
914 /*
915  * Unregister a receive function for this mac.  This removes the function
916  * from the list of receive functions for this mac.
917  */
918 void
919 mac_rx_remove(mac_handle_t mh, mac_rx_handle_t mrh)
920 {
921 	mac_impl_t		*mip = (mac_impl_t *)mh;
922 	mac_rx_fn_t		*mrfp = (mac_rx_fn_t *)mrh;
923 	mac_rx_fn_t		**pp;
924 	mac_rx_fn_t		*p;
925 
926 	/*
927 	 * Search the 'rx' callback list for the function closure.
928 	 */
929 	rw_enter(&(mip->mi_rx_lock), RW_WRITER);
930 	for (pp = &(mip->mi_mrfp); (p = *pp) != NULL; pp = &(p->mrf_nextp)) {
931 		if (p == mrfp)
932 			break;
933 	}
934 	ASSERT(p != NULL);
935 
936 	/* Remove it from the list. */
937 	*pp = p->mrf_nextp;
938 	kmem_free(mrfp, sizeof (mac_rx_fn_t));
939 	rw_exit(&(mip->mi_rx_lock));
940 }
941 
942 mac_txloop_handle_t
943 mac_txloop_add(mac_handle_t mh, mac_txloop_t tx, void *arg)
944 {
945 	mac_impl_t	*mip = (mac_impl_t *)mh;
946 	mac_txloop_fn_t	*mtfp;
947 
948 	mtfp = kmem_zalloc(sizeof (mac_txloop_fn_t), KM_SLEEP);
949 	mtfp->mtf_fn = tx;
950 	mtfp->mtf_arg = arg;
951 
952 	/*
953 	 * Add it to the head of the 'tx' callback list.
954 	 */
955 	rw_enter(&(mip->mi_txloop_lock), RW_WRITER);
956 	mtfp->mtf_nextp = mip->mi_mtfp;
957 	mip->mi_mtfp = mtfp;
958 	rw_exit(&(mip->mi_txloop_lock));
959 
960 	return ((mac_txloop_handle_t)mtfp);
961 }
962 
963 /*
964  * Unregister a transmit function for this mac.  This removes the function
965  * from the list of transmit functions for this mac.
966  */
967 void
968 mac_txloop_remove(mac_handle_t mh, mac_txloop_handle_t mth)
969 {
970 	mac_impl_t		*mip = (mac_impl_t *)mh;
971 	mac_txloop_fn_t		*mtfp = (mac_txloop_fn_t *)mth;
972 	mac_txloop_fn_t		**pp;
973 	mac_txloop_fn_t		*p;
974 
975 	/*
976 	 * Search the 'tx' callback list for the function.
977 	 */
978 	rw_enter(&(mip->mi_txloop_lock), RW_WRITER);
979 	for (pp = &(mip->mi_mtfp); (p = *pp) != NULL; pp = &(p->mtf_nextp)) {
980 		if (p == mtfp)
981 			break;
982 	}
983 	ASSERT(p != NULL);
984 
985 	/* Remove it from the list. */
986 	*pp = p->mtf_nextp;
987 	kmem_free(mtfp, sizeof (mac_txloop_fn_t));
988 	rw_exit(&(mip->mi_txloop_lock));
989 }
990 
991 void
992 mac_resource_set(mac_handle_t mh, mac_resource_add_t add, void *arg)
993 {
994 	mac_impl_t		*mip = (mac_impl_t *)mh;
995 
996 	/*
997 	 * Update the 'resource_add' callbacks.
998 	 */
999 	rw_enter(&(mip->mi_resource_lock), RW_WRITER);
1000 	mip->mi_resource_add = add;
1001 	mip->mi_resource_add_arg = arg;
1002 	rw_exit(&(mip->mi_resource_lock));
1003 }
1004 
1005 /*
1006  * Driver support functions.
1007  */
1008 
1009 int
1010 mac_register(mac_t *mp)
1011 {
1012 	int	err;
1013 	char	name[MAXNAMELEN], aggr_name[MAXNAMELEN];
1014 	struct devnames *dnp;
1015 
1016 #ifdef	DEBUG
1017 	if (strcmp(mp->m_ident, MAC_IDENT) != 0)
1018 		cmn_err(CE_WARN, "%s%d/%d: possible mac interface mismatch",
1019 		    ddi_driver_name(mp->m_dip),
1020 		    ddi_get_instance(mp->m_dip),
1021 		    mp->m_port);
1022 #endif	/* DEBUG */
1023 
1024 	ASSERT(!(mp->m_info.mi_addr_length & 1));
1025 
1026 	/*
1027 	 * Create a new mac_impl_t to pair with the mac_t.
1028 	 */
1029 	if ((err = i_mac_create(mp)) != 0)
1030 		return (err);
1031 
1032 	/*
1033 	 * Create a DDI_NT_MAC minor node such that libdevinfo(3lib) can be
1034 	 * used to search for mac interfaces.
1035 	 */
1036 	(void) sprintf(name, "%d", mp->m_port);
1037 	if (ddi_create_minor_node(mp->m_dip, name, S_IFCHR, mp->m_port,
1038 	    DDI_NT_MAC, 0) != DDI_SUCCESS) {
1039 		i_mac_destroy(mp);
1040 		return (EEXIST);
1041 	}
1042 
1043 	/*
1044 	 * Right now only the "aggr" driver creates nodes at mac_register
1045 	 * time, but it is expected that in the future with some
1046 	 * enhancement of devfs, all the drivers can create nodes here.
1047 	 */
1048 	if (strcmp(ddi_driver_name(mp->m_dip), "aggr") == 0) {
1049 		(void) snprintf(aggr_name, MAXNAMELEN, "aggr%u", mp->m_port);
1050 		err = dld_ppa_create(aggr_name, AGGR_DEV, mp->m_port, 0);
1051 		if (err != 0) {
1052 			ASSERT(err != EEXIST);
1053 			ddi_remove_minor_node(mp->m_dip, name);
1054 			i_mac_destroy(mp);
1055 			return (err);
1056 		}
1057 	}
1058 
1059 	/* set the gldv3 flag in dn_flags */
1060 	dnp = &devnamesp[ddi_driver_major(mp->m_dip)];
1061 	LOCK_DEV_OPS(&dnp->dn_lock);
1062 	dnp->dn_flags |= DN_GLDV3_DRIVER;
1063 	UNLOCK_DEV_OPS(&dnp->dn_lock);
1064 
1065 	cmn_err(CE_NOTE, "!%s%d/%d registered",
1066 	    ddi_driver_name(mp->m_dip),
1067 	    ddi_get_instance(mp->m_dip),
1068 	    mp->m_port);
1069 
1070 	return (0);
1071 }
1072 
1073 int
1074 mac_unregister(mac_t *mp)
1075 {
1076 	int		err;
1077 	char		name[MAXNAMELEN];
1078 	mac_impl_t	*mip = mp->m_impl;
1079 
1080 	/*
1081 	 * See if there are any other references to this mac_t (e.g., VLAN's).
1082 	 * If not, set mi_destroying to prevent any new VLAN's from being
1083 	 * created before we can perform the i_mac_destroy() below.
1084 	 */
1085 	ght_lock(i_mac_impl_hash, GHT_WRITE);
1086 	if (mip->mi_ref > 0) {
1087 		ght_unlock(i_mac_impl_hash);
1088 		return (EBUSY);
1089 	}
1090 	mip->mi_destroying = B_TRUE;
1091 	ght_unlock(i_mac_impl_hash);
1092 
1093 	if (strcmp(ddi_driver_name(mp->m_dip), "aggr") == 0) {
1094 		(void) snprintf(name, MAXNAMELEN, "aggr%u", mp->m_port);
1095 		if ((err = dld_ppa_destroy(name)) != 0)
1096 			return (err);
1097 	}
1098 
1099 	/*
1100 	 * Destroy the mac_impl_t.
1101 	 */
1102 	i_mac_destroy(mp);
1103 
1104 	/*
1105 	 * Remove the minor node.
1106 	 */
1107 	(void) sprintf(name, "%d", mp->m_port);
1108 	ddi_remove_minor_node(mp->m_dip, name);
1109 
1110 	cmn_err(CE_NOTE, "!%s%d/%d unregistered",
1111 	    ddi_driver_name(mp->m_dip),
1112 	    ddi_get_instance(mp->m_dip),
1113 	    mp->m_port);
1114 
1115 	return (0);
1116 }
1117 
1118 void
1119 mac_rx(mac_t *mp, mac_resource_handle_t mrh, mblk_t *bp)
1120 {
1121 	mac_impl_t	*mip = mp->m_impl;
1122 	mac_rx_fn_t	*mrfp;
1123 
1124 	/*
1125 	 * Call all registered receive functions.
1126 	 */
1127 	rw_enter(&mip->mi_rx_lock, RW_READER);
1128 	mrfp = mip->mi_mrfp;
1129 	if (mrfp == NULL) {
1130 		/* There are no registered receive functions. */
1131 		freemsgchain(bp);
1132 		rw_exit(&mip->mi_rx_lock);
1133 		return;
1134 	}
1135 	do {
1136 		mblk_t *recv_bp;
1137 
1138 		if (mrfp->mrf_nextp != NULL) {
1139 			/* XXX Do we bump a counter if copymsgchain() fails? */
1140 			recv_bp = copymsgchain(bp);
1141 		} else {
1142 			recv_bp = bp;
1143 		}
1144 		if (recv_bp != NULL)
1145 			mrfp->mrf_fn(mrfp->mrf_arg, mrh, recv_bp);
1146 		mrfp = mrfp->mrf_nextp;
1147 	} while (mrfp != NULL);
1148 	rw_exit(&mip->mi_rx_lock);
1149 }
1150 
1151 /*
1152  * Transmit function -- ONLY used when there are registered loopback listeners.
1153  */
1154 mblk_t *
1155 mac_txloop(void *arg, mblk_t *bp)
1156 {
1157 	mac_impl_t	*mip = arg;
1158 	mac_t		*mp = mip->mi_mp;
1159 	mac_txloop_fn_t	*mtfp;
1160 	mblk_t		*loop_bp, *resid_bp, *next_bp;
1161 
1162 	while (bp != NULL) {
1163 		next_bp = bp->b_next;
1164 		bp->b_next = NULL;
1165 
1166 		if ((loop_bp = copymsg(bp)) == NULL)
1167 			goto noresources;
1168 
1169 		if ((resid_bp = mp->m_tx(mp->m_driver, bp)) != NULL) {
1170 			ASSERT(resid_bp == bp);
1171 			freemsg(loop_bp);
1172 			goto noresources;
1173 		}
1174 
1175 		rw_enter(&mip->mi_txloop_lock, RW_READER);
1176 		mtfp = mip->mi_mtfp;
1177 		while (mtfp != NULL && loop_bp != NULL) {
1178 			bp = loop_bp;
1179 
1180 			/* XXX counter bump if copymsg() fails? */
1181 			if (mtfp->mtf_nextp != NULL)
1182 				loop_bp = copymsg(bp);
1183 			else
1184 				loop_bp = NULL;
1185 
1186 			mtfp->mtf_fn(mtfp->mtf_arg, bp);
1187 			mtfp = mtfp->mtf_nextp;
1188 		}
1189 		rw_exit(&mip->mi_txloop_lock);
1190 
1191 		/*
1192 		 * It's possible we've raced with the disabling of promiscuous
1193 		 * mode, in which case we can discard our copy.
1194 		 */
1195 		if (loop_bp != NULL)
1196 			freemsg(loop_bp);
1197 
1198 		bp = next_bp;
1199 	}
1200 
1201 	return (NULL);
1202 
1203 noresources:
1204 	bp->b_next = next_bp;
1205 	return (bp);
1206 }
1207 
1208 void
1209 mac_link_update(mac_t *mp, link_state_t link)
1210 {
1211 	mac_impl_t	*mip = mp->m_impl;
1212 
1213 	ASSERT(mip->mi_mp == mp);
1214 
1215 	/*
1216 	 * Save the link state.
1217 	 */
1218 	mip->mi_link = link;
1219 
1220 	/*
1221 	 * Send a MAC_NOTE_LINK notification.
1222 	 */
1223 	i_mac_notify(mip, MAC_NOTE_LINK);
1224 }
1225 
1226 void
1227 mac_unicst_update(mac_t *mp, const uint8_t *addr)
1228 {
1229 	mac_impl_t	*mip = mp->m_impl;
1230 
1231 	ASSERT(mip->mi_mp == mp);
1232 
1233 	/*
1234 	 * Save the address.
1235 	 */
1236 	bcopy(addr, mip->mi_addr, mip->mi_addr_length);
1237 
1238 	/*
1239 	 * Send a MAC_NOTE_UNICST notification.
1240 	 */
1241 	i_mac_notify(mip, MAC_NOTE_UNICST);
1242 }
1243 
1244 void
1245 mac_tx_update(mac_t *mp)
1246 {
1247 	mac_impl_t	*mip = mp->m_impl;
1248 
1249 	ASSERT(mip->mi_mp == mp);
1250 
1251 	/*
1252 	 * Send a MAC_NOTE_TX notification.
1253 	 */
1254 	i_mac_notify(mip, MAC_NOTE_TX);
1255 }
1256 
1257 void
1258 mac_resource_update(mac_t *mp)
1259 {
1260 	mac_impl_t	*mip = mp->m_impl;
1261 
1262 	ASSERT(mip->mi_mp == mp);
1263 
1264 	/*
1265 	 * Send a MAC_NOTE_RESOURCE notification.
1266 	 */
1267 	i_mac_notify(mip, MAC_NOTE_RESOURCE);
1268 }
1269 
1270 mac_resource_handle_t
1271 mac_resource_add(mac_t *mp, mac_resource_t *mrp)
1272 {
1273 	mac_impl_t		*mip = mp->m_impl;
1274 	mac_resource_handle_t	mrh;
1275 	mac_resource_add_t	add;
1276 	void			*arg;
1277 
1278 	rw_enter(&mip->mi_resource_lock, RW_READER);
1279 	add = mip->mi_resource_add;
1280 	arg = mip->mi_resource_add_arg;
1281 
1282 	mrh = add(arg, mrp);
1283 	rw_exit(&mip->mi_resource_lock);
1284 
1285 	return (mrh);
1286 }
1287 
1288 void
1289 mac_multicst_refresh(mac_t *mp, mac_multicst_t refresh, void *arg,
1290     boolean_t add)
1291 {
1292 	mac_impl_t		*mip = mp->m_impl;
1293 	mac_multicst_addr_t	*p;
1294 
1295 	/*
1296 	 * If no specific refresh function was given then default to the
1297 	 * driver's m_multicst entry point.
1298 	 */
1299 	if (refresh == NULL) {
1300 		refresh = mp->m_multicst;
1301 		arg = mp->m_driver;
1302 	}
1303 	ASSERT(refresh != NULL);
1304 
1305 	/*
1306 	 * Walk the multicast address list and call the refresh function for
1307 	 * each address.
1308 	 */
1309 	rw_enter(&(mip->mi_data_lock), RW_READER);
1310 	for (p = mip->mi_mmap; p != NULL; p = p->mma_nextp)
1311 		refresh(arg, add, p->mma_addr);
1312 	rw_exit(&(mip->mi_data_lock));
1313 }
1314 
1315 void
1316 mac_unicst_refresh(mac_t *mp, mac_unicst_t refresh, void *arg)
1317 {
1318 	mac_impl_t	*mip = mp->m_impl;
1319 	/*
1320 	 * If no specific refresh function was given then default to the
1321 	 * driver's m_unicst entry point.
1322 	 */
1323 	if (refresh == NULL) {
1324 		refresh = mp->m_unicst;
1325 		arg = mp->m_driver;
1326 	}
1327 	ASSERT(refresh != NULL);
1328 
1329 	/*
1330 	 * Call the refresh function with the current unicast address.
1331 	 */
1332 	refresh(arg, mip->mi_addr);
1333 }
1334 
1335 void
1336 mac_promisc_refresh(mac_t *mp, mac_promisc_t refresh, void *arg)
1337 {
1338 	mac_impl_t	*mip = mp->m_impl;
1339 
1340 	/*
1341 	 * If no specific refresh function was given then default to the
1342 	 * driver's m_promisc entry point.
1343 	 */
1344 	if (refresh == NULL) {
1345 		refresh = mp->m_promisc;
1346 		arg = mp->m_driver;
1347 	}
1348 	ASSERT(refresh != NULL);
1349 
1350 	/*
1351 	 * Call the refresh function with the current promiscuity.
1352 	 */
1353 	refresh(arg, (mip->mi_devpromisc != 0));
1354 }
1355 
1356 boolean_t
1357 mac_active_set(mac_handle_t mh)
1358 {
1359 	mac_impl_t *mip = (mac_impl_t *)mh;
1360 
1361 	mutex_enter(&mip->mi_activelink_lock);
1362 	if (mip->mi_activelink) {
1363 		mutex_exit(&mip->mi_activelink_lock);
1364 		return (B_FALSE);
1365 	}
1366 	mip->mi_activelink = B_TRUE;
1367 	mutex_exit(&mip->mi_activelink_lock);
1368 	return (B_TRUE);
1369 }
1370 
1371 void
1372 mac_active_clear(mac_handle_t mh)
1373 {
1374 	mac_impl_t *mip = (mac_impl_t *)mh;
1375 
1376 	mutex_enter(&mip->mi_activelink_lock);
1377 	ASSERT(mip->mi_activelink);
1378 	mip->mi_activelink = B_FALSE;
1379 	mutex_exit(&mip->mi_activelink_lock);
1380 }
1381