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