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