xref: /titanic_52/usr/src/uts/common/io/simnet/simnet.c (revision 0dc2366f7b9f9f36e10909b1e95edbf2a261c2ac)
1b509e89bSRishi Srivatsavai /*
2b509e89bSRishi Srivatsavai  * CDDL HEADER START
3b509e89bSRishi Srivatsavai  *
4b509e89bSRishi Srivatsavai  * The contents of this file are subject to the terms of the
5b509e89bSRishi Srivatsavai  * Common Development and Distribution License (the "License").
6b509e89bSRishi Srivatsavai  * You may not use this file except in compliance with the License.
7b509e89bSRishi Srivatsavai  *
8b509e89bSRishi Srivatsavai  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9b509e89bSRishi Srivatsavai  * or http://www.opensolaris.org/os/licensing.
10b509e89bSRishi Srivatsavai  * See the License for the specific language governing permissions
11b509e89bSRishi Srivatsavai  * and limitations under the License.
12b509e89bSRishi Srivatsavai  *
13b509e89bSRishi Srivatsavai  * When distributing Covered Code, include this CDDL HEADER in each
14b509e89bSRishi Srivatsavai  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15b509e89bSRishi Srivatsavai  * If applicable, add the following below this CDDL HEADER, with the
16b509e89bSRishi Srivatsavai  * fields enclosed by brackets "[]" replaced with your own identifying
17b509e89bSRishi Srivatsavai  * information: Portions Copyright [yyyy] [name of copyright owner]
18b509e89bSRishi Srivatsavai  *
19b509e89bSRishi Srivatsavai  * CDDL HEADER END
20b509e89bSRishi Srivatsavai  */
21b509e89bSRishi Srivatsavai /*
22*0dc2366fSVenugopal Iyer  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
23b509e89bSRishi Srivatsavai  * Use is subject to license terms.
24b509e89bSRishi Srivatsavai  */
25b509e89bSRishi Srivatsavai 
26b509e89bSRishi Srivatsavai /*
27b509e89bSRishi Srivatsavai  * Simulated network device (simnet) driver: simulates a pseudo GLDv3 network
28b509e89bSRishi Srivatsavai  * device. Can simulate an Ethernet or WiFi network device. In addition, another
29b509e89bSRishi Srivatsavai  * simnet instance can be attached as a peer to create a point-to-point link on
30b509e89bSRishi Srivatsavai  * the same system.
31b509e89bSRishi Srivatsavai  */
32b509e89bSRishi Srivatsavai 
33b509e89bSRishi Srivatsavai #include <sys/policy.h>
34b509e89bSRishi Srivatsavai #include <sys/conf.h>
35b509e89bSRishi Srivatsavai #include <sys/modctl.h>
36b509e89bSRishi Srivatsavai #include <sys/priv_names.h>
37b509e89bSRishi Srivatsavai #include <sys/dlpi.h>
38b509e89bSRishi Srivatsavai #include <net/simnet.h>
39b509e89bSRishi Srivatsavai #include <sys/ethernet.h>
40b509e89bSRishi Srivatsavai #include <sys/mac.h>
41b509e89bSRishi Srivatsavai #include <sys/dls.h>
42b509e89bSRishi Srivatsavai #include <sys/mac_ether.h>
43b509e89bSRishi Srivatsavai #include <sys/mac_provider.h>
44b509e89bSRishi Srivatsavai #include <sys/mac_client_priv.h>
45b509e89bSRishi Srivatsavai #include <sys/vlan.h>
46b509e89bSRishi Srivatsavai #include <sys/random.h>
47b509e89bSRishi Srivatsavai #include <sys/sysmacros.h>
48b509e89bSRishi Srivatsavai #include <sys/list.h>
49b509e89bSRishi Srivatsavai #include <sys/strsubr.h>
50b509e89bSRishi Srivatsavai #include <sys/strsun.h>
51b509e89bSRishi Srivatsavai #include <sys/atomic.h>
52b509e89bSRishi Srivatsavai #include <sys/mac_wifi.h>
53b509e89bSRishi Srivatsavai #include <sys/mac_impl.h>
54b509e89bSRishi Srivatsavai #include <inet/wifi_ioctl.h>
55b509e89bSRishi Srivatsavai #include <sys/thread.h>
56b509e89bSRishi Srivatsavai #include <sys/synch.h>
570f83d385SRishi Srivatsavai #include <sys/sunddi.h>
58b509e89bSRishi Srivatsavai 
59b509e89bSRishi Srivatsavai #include "simnet_impl.h"
60b509e89bSRishi Srivatsavai 
61b509e89bSRishi Srivatsavai #define	SIMNETINFO		"Simulated Network Driver"
62b509e89bSRishi Srivatsavai 
63b509e89bSRishi Srivatsavai static dev_info_t *simnet_dip;
640f83d385SRishi Srivatsavai static ddi_taskq_t *simnet_rxq;
65b509e89bSRishi Srivatsavai 
66b509e89bSRishi Srivatsavai static int simnet_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
67b509e89bSRishi Srivatsavai static int simnet_attach(dev_info_t *, ddi_attach_cmd_t);
68b509e89bSRishi Srivatsavai static int simnet_detach(dev_info_t *, ddi_detach_cmd_t);
69b509e89bSRishi Srivatsavai static int simnet_ioc_create(void *, intptr_t, int, cred_t *, int *);
70b509e89bSRishi Srivatsavai static int simnet_ioc_delete(void *, intptr_t, int, cred_t *, int *);
71b509e89bSRishi Srivatsavai static int simnet_ioc_info(void *, intptr_t, int, cred_t *, int *);
72b509e89bSRishi Srivatsavai static int simnet_ioc_modify(void *, intptr_t, int, cred_t *, int *);
73b509e89bSRishi Srivatsavai static uint8_t *mcastaddr_lookup(simnet_dev_t *, const uint8_t *);
74b509e89bSRishi Srivatsavai 
75b509e89bSRishi Srivatsavai static dld_ioc_info_t simnet_ioc_list[] = {
76b509e89bSRishi Srivatsavai 	{SIMNET_IOC_CREATE, DLDCOPYINOUT, sizeof (simnet_ioc_create_t),
772b24ab6bSSebastien Roy 	    simnet_ioc_create, secpolicy_dl_config},
78b509e89bSRishi Srivatsavai 	{SIMNET_IOC_DELETE, DLDCOPYIN, sizeof (simnet_ioc_delete_t),
792b24ab6bSSebastien Roy 	    simnet_ioc_delete, secpolicy_dl_config},
80b509e89bSRishi Srivatsavai 	{SIMNET_IOC_INFO, DLDCOPYINOUT, sizeof (simnet_ioc_info_t),
812b24ab6bSSebastien Roy 	    simnet_ioc_info, NULL},
82b509e89bSRishi Srivatsavai 	{SIMNET_IOC_MODIFY, DLDCOPYIN, sizeof (simnet_ioc_modify_t),
832b24ab6bSSebastien Roy 	    simnet_ioc_modify, secpolicy_dl_config}
84b509e89bSRishi Srivatsavai };
85b509e89bSRishi Srivatsavai 
86b509e89bSRishi Srivatsavai DDI_DEFINE_STREAM_OPS(simnet_dev_ops, nulldev, nulldev, simnet_attach,
87b509e89bSRishi Srivatsavai     simnet_detach, nodev, simnet_getinfo, D_MP, NULL,
88b509e89bSRishi Srivatsavai     ddi_quiesce_not_supported);
89b509e89bSRishi Srivatsavai 
90b509e89bSRishi Srivatsavai static struct modldrv simnet_modldrv = {
91b509e89bSRishi Srivatsavai 	&mod_driverops,		/* Type of module.  This one is a driver */
92b509e89bSRishi Srivatsavai 	SIMNETINFO,		/* short description */
93b509e89bSRishi Srivatsavai 	&simnet_dev_ops		/* driver specific ops */
94b509e89bSRishi Srivatsavai };
95b509e89bSRishi Srivatsavai 
96b509e89bSRishi Srivatsavai static struct modlinkage modlinkage = {
97b509e89bSRishi Srivatsavai 	MODREV_1, &simnet_modldrv, NULL
98b509e89bSRishi Srivatsavai };
99b509e89bSRishi Srivatsavai 
100b509e89bSRishi Srivatsavai /* MAC callback function declarations */
101b509e89bSRishi Srivatsavai static int simnet_m_start(void *);
102b509e89bSRishi Srivatsavai static void simnet_m_stop(void *);
103b509e89bSRishi Srivatsavai static int simnet_m_promisc(void *, boolean_t);
104b509e89bSRishi Srivatsavai static int simnet_m_multicst(void *, boolean_t, const uint8_t *);
105b509e89bSRishi Srivatsavai static int simnet_m_unicst(void *, const uint8_t *);
106b509e89bSRishi Srivatsavai static int simnet_m_stat(void *, uint_t, uint64_t *);
107b509e89bSRishi Srivatsavai static void simnet_m_ioctl(void *, queue_t *, mblk_t *);
108b509e89bSRishi Srivatsavai static mblk_t *simnet_m_tx(void *, mblk_t *);
109b509e89bSRishi Srivatsavai static int simnet_m_setprop(void *, const char *, mac_prop_id_t,
110b509e89bSRishi Srivatsavai     uint_t, const void *);
111b509e89bSRishi Srivatsavai static int simnet_m_getprop(void *, const char *, mac_prop_id_t,
112*0dc2366fSVenugopal Iyer     uint_t, void *);
113*0dc2366fSVenugopal Iyer static void simnet_m_propinfo(void *, const char *, mac_prop_id_t,
114*0dc2366fSVenugopal Iyer     mac_prop_info_handle_t);
115b509e89bSRishi Srivatsavai 
116b509e89bSRishi Srivatsavai static mac_callbacks_t simnet_m_callbacks = {
117*0dc2366fSVenugopal Iyer 	(MC_IOCTL | MC_SETPROP | MC_GETPROP | MC_PROPINFO),
118b509e89bSRishi Srivatsavai 	simnet_m_stat,
119b509e89bSRishi Srivatsavai 	simnet_m_start,
120b509e89bSRishi Srivatsavai 	simnet_m_stop,
121b509e89bSRishi Srivatsavai 	simnet_m_promisc,
122b509e89bSRishi Srivatsavai 	simnet_m_multicst,
123b509e89bSRishi Srivatsavai 	simnet_m_unicst,
124b509e89bSRishi Srivatsavai 	simnet_m_tx,
125*0dc2366fSVenugopal Iyer 	NULL,
126b509e89bSRishi Srivatsavai 	simnet_m_ioctl,
127b509e89bSRishi Srivatsavai 	NULL,
128b509e89bSRishi Srivatsavai 	NULL,
129b509e89bSRishi Srivatsavai 	NULL,
130b509e89bSRishi Srivatsavai 	simnet_m_setprop,
131*0dc2366fSVenugopal Iyer 	simnet_m_getprop,
132*0dc2366fSVenugopal Iyer 	simnet_m_propinfo
133b509e89bSRishi Srivatsavai };
134b509e89bSRishi Srivatsavai 
135b509e89bSRishi Srivatsavai /*
136b509e89bSRishi Srivatsavai  * simnet_dev_lock protects the simnet device list.
137b509e89bSRishi Srivatsavai  * sd_instlock in each simnet_dev_t protects access to
138b509e89bSRishi Srivatsavai  * a single simnet_dev_t.
139b509e89bSRishi Srivatsavai  */
140b509e89bSRishi Srivatsavai static krwlock_t	simnet_dev_lock;
141b509e89bSRishi Srivatsavai static list_t		simnet_dev_list;
142b509e89bSRishi Srivatsavai static int		simnet_count; /* Num of simnet instances */
143b509e89bSRishi Srivatsavai 
144b509e89bSRishi Srivatsavai int
145b509e89bSRishi Srivatsavai _init(void)
146b509e89bSRishi Srivatsavai {
147b509e89bSRishi Srivatsavai 	int	status;
148b509e89bSRishi Srivatsavai 
149b509e89bSRishi Srivatsavai 	mac_init_ops(&simnet_dev_ops, "simnet");
150b509e89bSRishi Srivatsavai 	status = mod_install(&modlinkage);
151b509e89bSRishi Srivatsavai 	if (status != DDI_SUCCESS)
152b509e89bSRishi Srivatsavai 		mac_fini_ops(&simnet_dev_ops);
153b509e89bSRishi Srivatsavai 
154b509e89bSRishi Srivatsavai 	return (status);
155b509e89bSRishi Srivatsavai }
156b509e89bSRishi Srivatsavai 
157b509e89bSRishi Srivatsavai int
158b509e89bSRishi Srivatsavai _fini(void)
159b509e89bSRishi Srivatsavai {
160b509e89bSRishi Srivatsavai 	int	status;
161b509e89bSRishi Srivatsavai 
162b509e89bSRishi Srivatsavai 	status = mod_remove(&modlinkage);
163b509e89bSRishi Srivatsavai 	if (status == DDI_SUCCESS)
164b509e89bSRishi Srivatsavai 		mac_fini_ops(&simnet_dev_ops);
165b509e89bSRishi Srivatsavai 
166b509e89bSRishi Srivatsavai 	return (status);
167b509e89bSRishi Srivatsavai }
168b509e89bSRishi Srivatsavai 
169b509e89bSRishi Srivatsavai int
170b509e89bSRishi Srivatsavai _info(struct modinfo *modinfop)
171b509e89bSRishi Srivatsavai {
172b509e89bSRishi Srivatsavai 	return (mod_info(&modlinkage, modinfop));
173b509e89bSRishi Srivatsavai }
174b509e89bSRishi Srivatsavai 
1750f83d385SRishi Srivatsavai static boolean_t
176b509e89bSRishi Srivatsavai simnet_init(void)
177b509e89bSRishi Srivatsavai {
1780f83d385SRishi Srivatsavai 	if ((simnet_rxq = ddi_taskq_create(simnet_dip, "simnet", 1,
1790f83d385SRishi Srivatsavai 	    TASKQ_DEFAULTPRI, 0)) == NULL)
1800f83d385SRishi Srivatsavai 		return (B_FALSE);
181b509e89bSRishi Srivatsavai 	rw_init(&simnet_dev_lock, NULL, RW_DEFAULT, NULL);
182b509e89bSRishi Srivatsavai 	list_create(&simnet_dev_list, sizeof (simnet_dev_t),
183b509e89bSRishi Srivatsavai 	    offsetof(simnet_dev_t, sd_listnode));
1840f83d385SRishi Srivatsavai 	return (B_TRUE);
185b509e89bSRishi Srivatsavai }
186b509e89bSRishi Srivatsavai 
187b509e89bSRishi Srivatsavai static void
188b509e89bSRishi Srivatsavai simnet_fini(void)
189b509e89bSRishi Srivatsavai {
190b509e89bSRishi Srivatsavai 	ASSERT(simnet_count == 0);
191b509e89bSRishi Srivatsavai 	rw_destroy(&simnet_dev_lock);
192b509e89bSRishi Srivatsavai 	list_destroy(&simnet_dev_list);
1930f83d385SRishi Srivatsavai 	ddi_taskq_destroy(simnet_rxq);
194b509e89bSRishi Srivatsavai }
195b509e89bSRishi Srivatsavai 
196b509e89bSRishi Srivatsavai /*ARGSUSED*/
197b509e89bSRishi Srivatsavai static int
198b509e89bSRishi Srivatsavai simnet_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
199b509e89bSRishi Srivatsavai     void **result)
200b509e89bSRishi Srivatsavai {
201b509e89bSRishi Srivatsavai 	switch (infocmd) {
202b509e89bSRishi Srivatsavai 	case DDI_INFO_DEVT2DEVINFO:
203b509e89bSRishi Srivatsavai 		*result = simnet_dip;
204b509e89bSRishi Srivatsavai 		return (DDI_SUCCESS);
205b509e89bSRishi Srivatsavai 	case DDI_INFO_DEVT2INSTANCE:
206b509e89bSRishi Srivatsavai 		*result = NULL;
207b509e89bSRishi Srivatsavai 		return (DDI_SUCCESS);
208b509e89bSRishi Srivatsavai 	}
209b509e89bSRishi Srivatsavai 	return (DDI_FAILURE);
210b509e89bSRishi Srivatsavai }
211b509e89bSRishi Srivatsavai 
212b509e89bSRishi Srivatsavai static int
213b509e89bSRishi Srivatsavai simnet_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
214b509e89bSRishi Srivatsavai {
215b509e89bSRishi Srivatsavai 	switch (cmd) {
216b509e89bSRishi Srivatsavai 	case DDI_ATTACH:
217b509e89bSRishi Srivatsavai 		if (ddi_get_instance(dip) != 0) {
218b509e89bSRishi Srivatsavai 			/* we only allow instance 0 to attach */
219b509e89bSRishi Srivatsavai 			return (DDI_FAILURE);
220b509e89bSRishi Srivatsavai 		}
2210f83d385SRishi Srivatsavai 
222b509e89bSRishi Srivatsavai 		if (dld_ioc_register(SIMNET_IOC, simnet_ioc_list,
223b509e89bSRishi Srivatsavai 		    DLDIOCCNT(simnet_ioc_list)) != 0)
224b509e89bSRishi Srivatsavai 			return (DDI_FAILURE);
225b509e89bSRishi Srivatsavai 
226b509e89bSRishi Srivatsavai 		simnet_dip = dip;
2270f83d385SRishi Srivatsavai 		if (!simnet_init())
2280f83d385SRishi Srivatsavai 			return (DDI_FAILURE);
229b509e89bSRishi Srivatsavai 		return (DDI_SUCCESS);
230b509e89bSRishi Srivatsavai 
231b509e89bSRishi Srivatsavai 	case DDI_RESUME:
232b509e89bSRishi Srivatsavai 		return (DDI_SUCCESS);
233b509e89bSRishi Srivatsavai 
234b509e89bSRishi Srivatsavai 	default:
235b509e89bSRishi Srivatsavai 		return (DDI_FAILURE);
236b509e89bSRishi Srivatsavai 	}
237b509e89bSRishi Srivatsavai }
238b509e89bSRishi Srivatsavai 
239b509e89bSRishi Srivatsavai /*ARGSUSED*/
240b509e89bSRishi Srivatsavai static int
241b509e89bSRishi Srivatsavai simnet_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
242b509e89bSRishi Srivatsavai {
243b509e89bSRishi Srivatsavai 	switch (cmd) {
244b509e89bSRishi Srivatsavai 	case DDI_DETACH:
245b509e89bSRishi Srivatsavai 		/*
246b509e89bSRishi Srivatsavai 		 * Allow the simnet instance to be detached only if there
247b509e89bSRishi Srivatsavai 		 * are no simnets configured.
248b509e89bSRishi Srivatsavai 		 */
249b509e89bSRishi Srivatsavai 		if (simnet_count > 0)
250b509e89bSRishi Srivatsavai 			return (DDI_FAILURE);
251b509e89bSRishi Srivatsavai 
252b509e89bSRishi Srivatsavai 		dld_ioc_unregister(SIMNET_IOC);
2530f83d385SRishi Srivatsavai 		simnet_fini();
2540f83d385SRishi Srivatsavai 		simnet_dip = NULL;
255b509e89bSRishi Srivatsavai 		return (DDI_SUCCESS);
256b509e89bSRishi Srivatsavai 
257b509e89bSRishi Srivatsavai 	case DDI_SUSPEND:
258b509e89bSRishi Srivatsavai 		return (DDI_SUCCESS);
259b509e89bSRishi Srivatsavai 
260b509e89bSRishi Srivatsavai 	default:
261b509e89bSRishi Srivatsavai 		return (DDI_FAILURE);
262b509e89bSRishi Srivatsavai 	}
263b509e89bSRishi Srivatsavai }
264b509e89bSRishi Srivatsavai 
265b509e89bSRishi Srivatsavai /* Caller must hold simnet_dev_lock */
266b509e89bSRishi Srivatsavai static simnet_dev_t *
267b509e89bSRishi Srivatsavai simnet_dev_lookup(datalink_id_t link_id)
268b509e89bSRishi Srivatsavai {
269b509e89bSRishi Srivatsavai 	simnet_dev_t *sdev;
270b509e89bSRishi Srivatsavai 
2710f83d385SRishi Srivatsavai 	ASSERT(RW_LOCK_HELD(&simnet_dev_lock));
272b509e89bSRishi Srivatsavai 	for (sdev = list_head(&simnet_dev_list); sdev != NULL;
273b509e89bSRishi Srivatsavai 	    sdev = list_next(&simnet_dev_list, sdev)) {
274b509e89bSRishi Srivatsavai 		if (!(sdev->sd_flags & SDF_SHUTDOWN) &&
275b509e89bSRishi Srivatsavai 		    (sdev->sd_link_id == link_id)) {
276b509e89bSRishi Srivatsavai 			atomic_inc_32(&sdev->sd_refcount);
277b509e89bSRishi Srivatsavai 			return (sdev);
278b509e89bSRishi Srivatsavai 		}
279b509e89bSRishi Srivatsavai 	}
280b509e89bSRishi Srivatsavai 
281b509e89bSRishi Srivatsavai 	return (NULL);
282b509e89bSRishi Srivatsavai }
283b509e89bSRishi Srivatsavai 
284b509e89bSRishi Srivatsavai static void
285b509e89bSRishi Srivatsavai simnet_wifidev_free(simnet_dev_t *sdev)
286b509e89bSRishi Srivatsavai {
287b509e89bSRishi Srivatsavai 	simnet_wifidev_t *wdev = sdev->sd_wifidev;
288b509e89bSRishi Srivatsavai 	int i;
289b509e89bSRishi Srivatsavai 
290b509e89bSRishi Srivatsavai 	for (i = 0; i < wdev->swd_esslist_num; i++) {
291b509e89bSRishi Srivatsavai 		kmem_free(wdev->swd_esslist[i],
292b509e89bSRishi Srivatsavai 		    sizeof (wl_ess_conf_t));
293b509e89bSRishi Srivatsavai 	}
294b509e89bSRishi Srivatsavai 	kmem_free(wdev, sizeof (simnet_wifidev_t));
295b509e89bSRishi Srivatsavai }
296b509e89bSRishi Srivatsavai 
297b509e89bSRishi Srivatsavai static void
298b509e89bSRishi Srivatsavai simnet_dev_unref(simnet_dev_t *sdev)
299b509e89bSRishi Srivatsavai {
300b509e89bSRishi Srivatsavai 
301b509e89bSRishi Srivatsavai 	ASSERT(sdev->sd_refcount > 0);
302b509e89bSRishi Srivatsavai 	if (atomic_dec_32_nv(&sdev->sd_refcount) != 0)
303b509e89bSRishi Srivatsavai 		return;
304b509e89bSRishi Srivatsavai 
305b509e89bSRishi Srivatsavai 	if (sdev->sd_mh != NULL)
306b509e89bSRishi Srivatsavai 		(void) mac_unregister(sdev->sd_mh);
307b509e89bSRishi Srivatsavai 
308b509e89bSRishi Srivatsavai 	if (sdev->sd_wifidev != NULL) {
309b509e89bSRishi Srivatsavai 		ASSERT(sdev->sd_type == DL_WIFI);
310b509e89bSRishi Srivatsavai 		simnet_wifidev_free(sdev);
311b509e89bSRishi Srivatsavai 	}
312b509e89bSRishi Srivatsavai 
313b509e89bSRishi Srivatsavai 	mutex_destroy(&sdev->sd_instlock);
314b509e89bSRishi Srivatsavai 	cv_destroy(&sdev->sd_threadwait);
315b509e89bSRishi Srivatsavai 	kmem_free(sdev->sd_mcastaddrs, ETHERADDRL * sdev->sd_mcastaddr_count);
316b509e89bSRishi Srivatsavai 	kmem_free(sdev, sizeof (*sdev));
317b509e89bSRishi Srivatsavai 	simnet_count--;
318b509e89bSRishi Srivatsavai }
319b509e89bSRishi Srivatsavai 
320b509e89bSRishi Srivatsavai static int
321b509e89bSRishi Srivatsavai simnet_init_wifi(simnet_dev_t *sdev, mac_register_t *mac)
322b509e89bSRishi Srivatsavai {
323b509e89bSRishi Srivatsavai 	wifi_data_t		wd = { 0 };
324b509e89bSRishi Srivatsavai 	int err;
325b509e89bSRishi Srivatsavai 
326b509e89bSRishi Srivatsavai 	sdev->sd_wifidev = kmem_zalloc(sizeof (simnet_wifidev_t), KM_NOSLEEP);
327b509e89bSRishi Srivatsavai 	if (sdev->sd_wifidev == NULL)
328b509e89bSRishi Srivatsavai 		return (ENOMEM);
329b509e89bSRishi Srivatsavai 
330b509e89bSRishi Srivatsavai 	sdev->sd_wifidev->swd_sdev = sdev;
331b509e89bSRishi Srivatsavai 	sdev->sd_wifidev->swd_linkstatus = WL_NOTCONNECTED;
332b509e89bSRishi Srivatsavai 	wd.wd_secalloc = WIFI_SEC_NONE;
333b509e89bSRishi Srivatsavai 	wd.wd_opmode = IEEE80211_M_STA;
334b509e89bSRishi Srivatsavai 	mac->m_type_ident = MAC_PLUGIN_IDENT_WIFI;
335b509e89bSRishi Srivatsavai 	mac->m_max_sdu = IEEE80211_MTU;
336b509e89bSRishi Srivatsavai 	mac->m_pdata = &wd;
337b509e89bSRishi Srivatsavai 	mac->m_pdata_size = sizeof (wd);
338b509e89bSRishi Srivatsavai 	err = mac_register(mac, &sdev->sd_mh);
339b509e89bSRishi Srivatsavai 	return (err);
340b509e89bSRishi Srivatsavai }
341b509e89bSRishi Srivatsavai 
342b509e89bSRishi Srivatsavai static int
343b509e89bSRishi Srivatsavai simnet_init_ether(simnet_dev_t *sdev, mac_register_t *mac)
344b509e89bSRishi Srivatsavai {
345b509e89bSRishi Srivatsavai 	int err;
346b509e89bSRishi Srivatsavai 
347b509e89bSRishi Srivatsavai 	mac->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
348b509e89bSRishi Srivatsavai 	mac->m_max_sdu = SIMNET_MAX_MTU;
349b509e89bSRishi Srivatsavai 	mac->m_margin = VLAN_TAGSZ;
350b509e89bSRishi Srivatsavai 	err = mac_register(mac, &sdev->sd_mh);
351b509e89bSRishi Srivatsavai 	return (err);
352b509e89bSRishi Srivatsavai }
353b509e89bSRishi Srivatsavai 
354b509e89bSRishi Srivatsavai static int
355b509e89bSRishi Srivatsavai simnet_init_mac(simnet_dev_t *sdev)
356b509e89bSRishi Srivatsavai {
357b509e89bSRishi Srivatsavai 	mac_register_t *mac;
358b509e89bSRishi Srivatsavai 	int err;
359b509e89bSRishi Srivatsavai 
360b509e89bSRishi Srivatsavai 	if ((mac = mac_alloc(MAC_VERSION)) == NULL)
361b509e89bSRishi Srivatsavai 		return (ENOMEM);
362b509e89bSRishi Srivatsavai 
363b509e89bSRishi Srivatsavai 	mac->m_driver = sdev;
364b509e89bSRishi Srivatsavai 	mac->m_dip = simnet_dip;
365b509e89bSRishi Srivatsavai 	mac->m_instance = (uint_t)-1;
366b509e89bSRishi Srivatsavai 	mac->m_src_addr = sdev->sd_mac_addr;
367b509e89bSRishi Srivatsavai 	mac->m_callbacks = &simnet_m_callbacks;
368b509e89bSRishi Srivatsavai 	mac->m_min_sdu = 0;
369b509e89bSRishi Srivatsavai 
370b509e89bSRishi Srivatsavai 	if (sdev->sd_type == DL_ETHER)
371b509e89bSRishi Srivatsavai 		err = simnet_init_ether(sdev, mac);
372b509e89bSRishi Srivatsavai 	else if (sdev->sd_type == DL_WIFI)
373b509e89bSRishi Srivatsavai 		err = simnet_init_wifi(sdev, mac);
374b509e89bSRishi Srivatsavai 	else
375b509e89bSRishi Srivatsavai 		err = EINVAL;
376b509e89bSRishi Srivatsavai 
377b509e89bSRishi Srivatsavai 	mac_free(mac);
378b509e89bSRishi Srivatsavai 	return (err);
379b509e89bSRishi Srivatsavai }
380b509e89bSRishi Srivatsavai 
381b509e89bSRishi Srivatsavai /* ARGSUSED */
382b509e89bSRishi Srivatsavai static int
383b509e89bSRishi Srivatsavai simnet_ioc_create(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp)
384b509e89bSRishi Srivatsavai {
385b509e89bSRishi Srivatsavai 	simnet_ioc_create_t *create_arg = karg;
386b509e89bSRishi Srivatsavai 	simnet_dev_t *sdev;
387b509e89bSRishi Srivatsavai 	simnet_dev_t *sdev_tmp;
388b509e89bSRishi Srivatsavai 	int err = 0;
389b509e89bSRishi Srivatsavai 
390b509e89bSRishi Srivatsavai 	sdev = kmem_zalloc(sizeof (*sdev), KM_NOSLEEP);
391b509e89bSRishi Srivatsavai 	if (sdev == NULL)
392b509e89bSRishi Srivatsavai 		return (ENOMEM);
393b509e89bSRishi Srivatsavai 
394b509e89bSRishi Srivatsavai 	rw_enter(&simnet_dev_lock, RW_WRITER);
395b509e89bSRishi Srivatsavai 	if ((sdev_tmp = simnet_dev_lookup(create_arg->sic_link_id)) != NULL) {
396b509e89bSRishi Srivatsavai 		simnet_dev_unref(sdev_tmp);
397b509e89bSRishi Srivatsavai 		rw_exit(&simnet_dev_lock);
398b509e89bSRishi Srivatsavai 		kmem_free(sdev, sizeof (*sdev));
399b509e89bSRishi Srivatsavai 		return (EEXIST);
400b509e89bSRishi Srivatsavai 	}
401b509e89bSRishi Srivatsavai 
402b509e89bSRishi Srivatsavai 	sdev->sd_type = create_arg->sic_type;
403b509e89bSRishi Srivatsavai 	sdev->sd_link_id = create_arg->sic_link_id;
4042b24ab6bSSebastien Roy 	sdev->sd_zoneid = crgetzoneid(cred);
405b509e89bSRishi Srivatsavai 	sdev->sd_refcount++;
406b509e89bSRishi Srivatsavai 	mutex_init(&sdev->sd_instlock, NULL, MUTEX_DRIVER, NULL);
407b509e89bSRishi Srivatsavai 	cv_init(&sdev->sd_threadwait, NULL, CV_DRIVER, NULL);
408b509e89bSRishi Srivatsavai 	simnet_count++;
409b509e89bSRishi Srivatsavai 
410b509e89bSRishi Srivatsavai 	/* Simnets created from configuration on boot pass saved MAC address */
411b509e89bSRishi Srivatsavai 	if (create_arg->sic_mac_len == 0) {
412b509e89bSRishi Srivatsavai 		/* Generate random MAC address */
413b509e89bSRishi Srivatsavai 		(void) random_get_pseudo_bytes(sdev->sd_mac_addr, ETHERADDRL);
414b509e89bSRishi Srivatsavai 		/* Ensure MAC address is not multicast and is local */
415b509e89bSRishi Srivatsavai 		sdev->sd_mac_addr[0] = (sdev->sd_mac_addr[0] & ~1) | 2;
416b509e89bSRishi Srivatsavai 		sdev->sd_mac_len = ETHERADDRL;
417b509e89bSRishi Srivatsavai 	} else {
418b509e89bSRishi Srivatsavai 		(void) memcpy(sdev->sd_mac_addr, create_arg->sic_mac_addr,
419b509e89bSRishi Srivatsavai 		    create_arg->sic_mac_len);
420b509e89bSRishi Srivatsavai 		sdev->sd_mac_len = create_arg->sic_mac_len;
421b509e89bSRishi Srivatsavai 	}
422b509e89bSRishi Srivatsavai 
423b509e89bSRishi Srivatsavai 	if ((err = simnet_init_mac(sdev)) != 0) {
424b509e89bSRishi Srivatsavai 		simnet_dev_unref(sdev);
425b509e89bSRishi Srivatsavai 		goto exit;
426b509e89bSRishi Srivatsavai 	}
427b509e89bSRishi Srivatsavai 
4282b24ab6bSSebastien Roy 	if ((err = dls_devnet_create(sdev->sd_mh, sdev->sd_link_id,
4292b24ab6bSSebastien Roy 	    crgetzoneid(cred))) != 0) {
430b509e89bSRishi Srivatsavai 		simnet_dev_unref(sdev);
431b509e89bSRishi Srivatsavai 		goto exit;
432b509e89bSRishi Srivatsavai 	}
433b509e89bSRishi Srivatsavai 
434b509e89bSRishi Srivatsavai 	mac_link_update(sdev->sd_mh, LINK_STATE_UP);
435b509e89bSRishi Srivatsavai 	mac_tx_update(sdev->sd_mh);
436b509e89bSRishi Srivatsavai 	list_insert_tail(&simnet_dev_list, sdev);
437b509e89bSRishi Srivatsavai 
438b509e89bSRishi Srivatsavai 	/* Always return MAC address back to caller */
439b509e89bSRishi Srivatsavai 	(void) memcpy(create_arg->sic_mac_addr, sdev->sd_mac_addr,
440b509e89bSRishi Srivatsavai 	    sdev->sd_mac_len);
441b509e89bSRishi Srivatsavai 	create_arg->sic_mac_len = sdev->sd_mac_len;
442b509e89bSRishi Srivatsavai exit:
443b509e89bSRishi Srivatsavai 	rw_exit(&simnet_dev_lock);
444b509e89bSRishi Srivatsavai 	return (err);
445b509e89bSRishi Srivatsavai }
446b509e89bSRishi Srivatsavai 
447b509e89bSRishi Srivatsavai /* Caller must hold writer simnet_dev_lock */
448b509e89bSRishi Srivatsavai static datalink_id_t
449b509e89bSRishi Srivatsavai simnet_remove_peer(simnet_dev_t *sdev)
450b509e89bSRishi Srivatsavai {
451b509e89bSRishi Srivatsavai 	simnet_dev_t *sdev_peer;
452b509e89bSRishi Srivatsavai 	datalink_id_t peer_link_id = DATALINK_INVALID_LINKID;
453b509e89bSRishi Srivatsavai 
4540f83d385SRishi Srivatsavai 	ASSERT(RW_WRITE_HELD(&simnet_dev_lock));
455b509e89bSRishi Srivatsavai 	if ((sdev_peer = sdev->sd_peer_dev) != NULL) {
456b509e89bSRishi Srivatsavai 		ASSERT(sdev == sdev_peer->sd_peer_dev);
457b509e89bSRishi Srivatsavai 		sdev_peer->sd_peer_dev = NULL;
458b509e89bSRishi Srivatsavai 		sdev->sd_peer_dev = NULL;
459b509e89bSRishi Srivatsavai 		peer_link_id = sdev_peer->sd_link_id;
460b509e89bSRishi Srivatsavai 		/* Release previous references held on both simnets */
461b509e89bSRishi Srivatsavai 		simnet_dev_unref(sdev_peer);
462b509e89bSRishi Srivatsavai 		simnet_dev_unref(sdev);
463b509e89bSRishi Srivatsavai 	}
464b509e89bSRishi Srivatsavai 
465b509e89bSRishi Srivatsavai 	return (peer_link_id);
466b509e89bSRishi Srivatsavai }
467b509e89bSRishi Srivatsavai 
468b509e89bSRishi Srivatsavai /* ARGSUSED */
469b509e89bSRishi Srivatsavai static int
470b509e89bSRishi Srivatsavai simnet_ioc_modify(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp)
471b509e89bSRishi Srivatsavai {
472b509e89bSRishi Srivatsavai 	simnet_ioc_modify_t *modify_arg = karg;
473b509e89bSRishi Srivatsavai 	simnet_dev_t *sdev;
474b509e89bSRishi Srivatsavai 	simnet_dev_t *sdev_peer = NULL;
475b509e89bSRishi Srivatsavai 
476b509e89bSRishi Srivatsavai 	rw_enter(&simnet_dev_lock, RW_WRITER);
477b509e89bSRishi Srivatsavai 	if ((sdev = simnet_dev_lookup(modify_arg->sim_link_id)) == NULL) {
478b509e89bSRishi Srivatsavai 		rw_exit(&simnet_dev_lock);
479b509e89bSRishi Srivatsavai 		return (ENOENT);
480b509e89bSRishi Srivatsavai 	}
481b509e89bSRishi Srivatsavai 
4822b24ab6bSSebastien Roy 	if (sdev->sd_zoneid != crgetzoneid(cred)) {
4832b24ab6bSSebastien Roy 		rw_exit(&simnet_dev_lock);
4842b24ab6bSSebastien Roy 		simnet_dev_unref(sdev);
4852b24ab6bSSebastien Roy 		return (ENOENT);
4862b24ab6bSSebastien Roy 	}
4872b24ab6bSSebastien Roy 
488b509e89bSRishi Srivatsavai 	if (sdev->sd_link_id == modify_arg->sim_peer_link_id) {
489b509e89bSRishi Srivatsavai 		/* Cannot peer with self */
490b509e89bSRishi Srivatsavai 		rw_exit(&simnet_dev_lock);
491b509e89bSRishi Srivatsavai 		simnet_dev_unref(sdev);
492b509e89bSRishi Srivatsavai 		return (EINVAL);
493b509e89bSRishi Srivatsavai 	}
494b509e89bSRishi Srivatsavai 
495b509e89bSRishi Srivatsavai 	if (sdev->sd_peer_dev != NULL && sdev->sd_peer_dev->sd_link_id ==
496b509e89bSRishi Srivatsavai 	    modify_arg->sim_peer_link_id) {
497b509e89bSRishi Srivatsavai 		/* Nothing to modify */
498b509e89bSRishi Srivatsavai 		rw_exit(&simnet_dev_lock);
499b509e89bSRishi Srivatsavai 		simnet_dev_unref(sdev);
500b509e89bSRishi Srivatsavai 		return (0);
501b509e89bSRishi Srivatsavai 	}
502b509e89bSRishi Srivatsavai 
5032b24ab6bSSebastien Roy 	if (modify_arg->sim_peer_link_id != DATALINK_INVALID_LINKID) {
5042b24ab6bSSebastien Roy 		sdev_peer = simnet_dev_lookup(modify_arg->sim_peer_link_id);
5052b24ab6bSSebastien Roy 		if (sdev_peer == NULL) {
506b509e89bSRishi Srivatsavai 			/* Peer simnet device not available */
507b509e89bSRishi Srivatsavai 			rw_exit(&simnet_dev_lock);
508b509e89bSRishi Srivatsavai 			simnet_dev_unref(sdev);
509b509e89bSRishi Srivatsavai 			return (ENOENT);
510b509e89bSRishi Srivatsavai 		}
5112b24ab6bSSebastien Roy 		if (sdev_peer->sd_zoneid != sdev->sd_zoneid) {
5122b24ab6bSSebastien Roy 			/* The two peers must be in the same zone (for now). */
5132b24ab6bSSebastien Roy 			rw_exit(&simnet_dev_lock);
5142b24ab6bSSebastien Roy 			simnet_dev_unref(sdev);
5152b24ab6bSSebastien Roy 			simnet_dev_unref(sdev_peer);
5162b24ab6bSSebastien Roy 			return (EACCES);
5172b24ab6bSSebastien Roy 		}
5182b24ab6bSSebastien Roy 	}
519b509e89bSRishi Srivatsavai 
520b509e89bSRishi Srivatsavai 	/* First remove any previous peer */
521b509e89bSRishi Srivatsavai 	(void) simnet_remove_peer(sdev);
522b509e89bSRishi Srivatsavai 
523b509e89bSRishi Srivatsavai 	if (sdev_peer != NULL) {
524b509e89bSRishi Srivatsavai 		/* Remove any previous peer of sdev_peer */
525b509e89bSRishi Srivatsavai 		(void) simnet_remove_peer(sdev_peer);
526b509e89bSRishi Srivatsavai 		/* Update both devices with the new peer */
527b509e89bSRishi Srivatsavai 		sdev_peer->sd_peer_dev = sdev;
528b509e89bSRishi Srivatsavai 		sdev->sd_peer_dev = sdev_peer;
529b509e89bSRishi Srivatsavai 		/* Hold references on both devices */
530b509e89bSRishi Srivatsavai 	} else {
531b509e89bSRishi Srivatsavai 		/* Release sdev lookup reference */
532b509e89bSRishi Srivatsavai 		simnet_dev_unref(sdev);
533b509e89bSRishi Srivatsavai 	}
534b509e89bSRishi Srivatsavai 
535b509e89bSRishi Srivatsavai 	rw_exit(&simnet_dev_lock);
536b509e89bSRishi Srivatsavai 	return (0);
537b509e89bSRishi Srivatsavai }
538b509e89bSRishi Srivatsavai 
539b509e89bSRishi Srivatsavai /* ARGSUSED */
540b509e89bSRishi Srivatsavai static int
541b509e89bSRishi Srivatsavai simnet_ioc_delete(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp)
542b509e89bSRishi Srivatsavai {
543b509e89bSRishi Srivatsavai 	int err;
544b509e89bSRishi Srivatsavai 	simnet_dev_t *sdev;
545b509e89bSRishi Srivatsavai 	simnet_dev_t *sdev_peer;
546b509e89bSRishi Srivatsavai 	simnet_ioc_delete_t *delete_arg = karg;
547b509e89bSRishi Srivatsavai 	datalink_id_t tmpid;
548b509e89bSRishi Srivatsavai 	datalink_id_t peerid;
549b509e89bSRishi Srivatsavai 
550b509e89bSRishi Srivatsavai 	rw_enter(&simnet_dev_lock, RW_WRITER);
551b509e89bSRishi Srivatsavai 	if ((sdev = simnet_dev_lookup(delete_arg->sid_link_id)) == NULL) {
552b509e89bSRishi Srivatsavai 		rw_exit(&simnet_dev_lock);
553b509e89bSRishi Srivatsavai 		return (ENOENT);
554b509e89bSRishi Srivatsavai 	}
555b509e89bSRishi Srivatsavai 
5562b24ab6bSSebastien Roy 	if (sdev->sd_zoneid != crgetzoneid(cred)) {
5572b24ab6bSSebastien Roy 		rw_exit(&simnet_dev_lock);
5582b24ab6bSSebastien Roy 		simnet_dev_unref(sdev);
5592b24ab6bSSebastien Roy 		return (ENOENT);
5602b24ab6bSSebastien Roy 	}
5612b24ab6bSSebastien Roy 
562b509e89bSRishi Srivatsavai 	if ((err = dls_devnet_destroy(sdev->sd_mh, &tmpid, B_TRUE)) != 0) {
563b509e89bSRishi Srivatsavai 		rw_exit(&simnet_dev_lock);
564b509e89bSRishi Srivatsavai 		simnet_dev_unref(sdev);
565b509e89bSRishi Srivatsavai 		return (err);
566b509e89bSRishi Srivatsavai 	}
567b509e89bSRishi Srivatsavai 
568b509e89bSRishi Srivatsavai 	ASSERT(sdev->sd_link_id == tmpid);
569b509e89bSRishi Srivatsavai 	/* Remove any attached peer link */
570b509e89bSRishi Srivatsavai 	peerid = simnet_remove_peer(sdev);
571b509e89bSRishi Srivatsavai 
572b509e89bSRishi Srivatsavai 	/* Prevent new threads from using the instance */
573b509e89bSRishi Srivatsavai 	mutex_enter(&sdev->sd_instlock);
574b509e89bSRishi Srivatsavai 	sdev->sd_flags |= SDF_SHUTDOWN;
575b509e89bSRishi Srivatsavai 	/* Wait until all active threads using the instance exit */
576b509e89bSRishi Srivatsavai 	while (sdev->sd_threadcount > 0) {
577b509e89bSRishi Srivatsavai 		if (cv_wait_sig(&sdev->sd_threadwait,
578b509e89bSRishi Srivatsavai 		    &sdev->sd_instlock) == 0)  {
579b509e89bSRishi Srivatsavai 			/* Signaled */
580b509e89bSRishi Srivatsavai 			mutex_exit(&sdev->sd_instlock);
581b509e89bSRishi Srivatsavai 			err = EINTR;
582b509e89bSRishi Srivatsavai 			goto fail;
583b509e89bSRishi Srivatsavai 		}
584b509e89bSRishi Srivatsavai 	}
585b509e89bSRishi Srivatsavai 	mutex_exit(&sdev->sd_instlock);
586b509e89bSRishi Srivatsavai 
587b509e89bSRishi Srivatsavai 	/* Try disabling the MAC */
588b509e89bSRishi Srivatsavai 	if ((err = mac_disable(sdev->sd_mh)) != 0)
589b509e89bSRishi Srivatsavai 		goto fail;
590b509e89bSRishi Srivatsavai 
591b509e89bSRishi Srivatsavai 	list_remove(&simnet_dev_list, sdev);
592b509e89bSRishi Srivatsavai 	rw_exit(&simnet_dev_lock);
593b509e89bSRishi Srivatsavai 	simnet_dev_unref(sdev); /* Release lookup ref */
594b509e89bSRishi Srivatsavai 	/* Releasing the last ref performs sdev/mem free */
595b509e89bSRishi Srivatsavai 	simnet_dev_unref(sdev);
596b509e89bSRishi Srivatsavai 	return (err);
597b509e89bSRishi Srivatsavai fail:
598b509e89bSRishi Srivatsavai 	/* Re-create simnet instance and add any previous peer */
5992b24ab6bSSebastien Roy 	(void) dls_devnet_create(sdev->sd_mh, sdev->sd_link_id,
6002b24ab6bSSebastien Roy 	    crgetzoneid(cred));
601b509e89bSRishi Srivatsavai 	sdev->sd_flags &= ~SDF_SHUTDOWN;
602b509e89bSRishi Srivatsavai 
603b509e89bSRishi Srivatsavai 	ASSERT(sdev->sd_peer_dev == NULL);
604b509e89bSRishi Srivatsavai 	if (peerid != DATALINK_INVALID_LINKID &&
605b509e89bSRishi Srivatsavai 	    ((sdev_peer = simnet_dev_lookup(peerid)) != NULL)) {
606b509e89bSRishi Srivatsavai 		/* Attach peer device back */
607b509e89bSRishi Srivatsavai 		ASSERT(sdev_peer->sd_peer_dev == NULL);
608b509e89bSRishi Srivatsavai 		sdev_peer->sd_peer_dev = sdev;
609b509e89bSRishi Srivatsavai 		sdev->sd_peer_dev = sdev_peer;
610b509e89bSRishi Srivatsavai 		/* Hold reference on both devices */
611b509e89bSRishi Srivatsavai 	} else {
612b509e89bSRishi Srivatsavai 		/*
613b509e89bSRishi Srivatsavai 		 * No previous peer or previous peer no longer
614b509e89bSRishi Srivatsavai 		 * available so release lookup reference.
615b509e89bSRishi Srivatsavai 		 */
616b509e89bSRishi Srivatsavai 		simnet_dev_unref(sdev);
617b509e89bSRishi Srivatsavai 	}
618b509e89bSRishi Srivatsavai 
619b509e89bSRishi Srivatsavai 	rw_exit(&simnet_dev_lock);
620b509e89bSRishi Srivatsavai 	return (err);
621b509e89bSRishi Srivatsavai }
622b509e89bSRishi Srivatsavai 
623b509e89bSRishi Srivatsavai /* ARGSUSED */
624b509e89bSRishi Srivatsavai static int
625b509e89bSRishi Srivatsavai simnet_ioc_info(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp)
626b509e89bSRishi Srivatsavai {
627b509e89bSRishi Srivatsavai 	simnet_ioc_info_t *info_arg = karg;
628b509e89bSRishi Srivatsavai 	simnet_dev_t *sdev;
629b509e89bSRishi Srivatsavai 
6302b24ab6bSSebastien Roy 	/* Make sure that the simnet link is visible from the caller's zone. */
6312b24ab6bSSebastien Roy 	if (!dls_devnet_islinkvisible(info_arg->sii_link_id, crgetzoneid(cred)))
6322b24ab6bSSebastien Roy 		return (ENOENT);
6332b24ab6bSSebastien Roy 
634b509e89bSRishi Srivatsavai 	rw_enter(&simnet_dev_lock, RW_READER);
635b509e89bSRishi Srivatsavai 	if ((sdev = simnet_dev_lookup(info_arg->sii_link_id)) == NULL) {
636b509e89bSRishi Srivatsavai 		rw_exit(&simnet_dev_lock);
637b509e89bSRishi Srivatsavai 		return (ENOENT);
638b509e89bSRishi Srivatsavai 	}
639b509e89bSRishi Srivatsavai 
640b509e89bSRishi Srivatsavai 	(void) memcpy(info_arg->sii_mac_addr, sdev->sd_mac_addr,
641b509e89bSRishi Srivatsavai 	    sdev->sd_mac_len);
642b509e89bSRishi Srivatsavai 	info_arg->sii_mac_len = sdev->sd_mac_len;
643b509e89bSRishi Srivatsavai 	info_arg->sii_type = sdev->sd_type;
644b509e89bSRishi Srivatsavai 	if (sdev->sd_peer_dev != NULL)
645b509e89bSRishi Srivatsavai 		info_arg->sii_peer_link_id = sdev->sd_peer_dev->sd_link_id;
646b509e89bSRishi Srivatsavai 	rw_exit(&simnet_dev_lock);
647b509e89bSRishi Srivatsavai 	simnet_dev_unref(sdev);
648b509e89bSRishi Srivatsavai 	return (0);
649b509e89bSRishi Srivatsavai }
650b509e89bSRishi Srivatsavai 
6510f83d385SRishi Srivatsavai static boolean_t
6520f83d385SRishi Srivatsavai simnet_thread_ref(simnet_dev_t *sdev)
653b509e89bSRishi Srivatsavai {
6540f83d385SRishi Srivatsavai 	mutex_enter(&sdev->sd_instlock);
6550f83d385SRishi Srivatsavai 	if (sdev->sd_flags & SDF_SHUTDOWN ||
6560f83d385SRishi Srivatsavai 	    !(sdev->sd_flags & SDF_STARTED)) {
6570f83d385SRishi Srivatsavai 		mutex_exit(&sdev->sd_instlock);
6580f83d385SRishi Srivatsavai 		return (B_FALSE);
6590f83d385SRishi Srivatsavai 	}
6600f83d385SRishi Srivatsavai 	sdev->sd_threadcount++;
6610f83d385SRishi Srivatsavai 	mutex_exit(&sdev->sd_instlock);
6620f83d385SRishi Srivatsavai 	return (B_TRUE);
6630f83d385SRishi Srivatsavai }
6640f83d385SRishi Srivatsavai 
6650f83d385SRishi Srivatsavai static void
6660f83d385SRishi Srivatsavai simnet_thread_unref(simnet_dev_t *sdev)
6670f83d385SRishi Srivatsavai {
6680f83d385SRishi Srivatsavai 	mutex_enter(&sdev->sd_instlock);
6690f83d385SRishi Srivatsavai 	if (--sdev->sd_threadcount == 0)
6700f83d385SRishi Srivatsavai 		cv_broadcast(&sdev->sd_threadwait);
6710f83d385SRishi Srivatsavai 	mutex_exit(&sdev->sd_instlock);
6720f83d385SRishi Srivatsavai }
6730f83d385SRishi Srivatsavai 
6740f83d385SRishi Srivatsavai static void
6750f83d385SRishi Srivatsavai simnet_rx(void *arg)
6760f83d385SRishi Srivatsavai {
6770f83d385SRishi Srivatsavai 	mblk_t *mp = arg;
678b509e89bSRishi Srivatsavai 	mac_header_info_t hdr_info;
6790f83d385SRishi Srivatsavai 	simnet_dev_t *sdev;
6800f83d385SRishi Srivatsavai 
6810f83d385SRishi Srivatsavai 	sdev = (simnet_dev_t *)mp->b_next;
6820f83d385SRishi Srivatsavai 	mp->b_next = NULL;
683b509e89bSRishi Srivatsavai 
684b509e89bSRishi Srivatsavai 	/* Check for valid packet header */
685b509e89bSRishi Srivatsavai 	if (mac_header_info(sdev->sd_mh, mp, &hdr_info) != 0) {
686b509e89bSRishi Srivatsavai 		freemsg(mp);
687b509e89bSRishi Srivatsavai 		sdev->sd_stats.recv_errors++;
6880f83d385SRishi Srivatsavai 		goto rx_done;
689b509e89bSRishi Srivatsavai 	}
690b509e89bSRishi Srivatsavai 
691b509e89bSRishi Srivatsavai 	/*
692b509e89bSRishi Srivatsavai 	 * When we are NOT in promiscuous mode we only receive
693b509e89bSRishi Srivatsavai 	 * unicast packets addressed to us and multicast packets that
694b509e89bSRishi Srivatsavai 	 * MAC clients have requested.
695b509e89bSRishi Srivatsavai 	 */
696b509e89bSRishi Srivatsavai 	if (!sdev->sd_promisc &&
697b509e89bSRishi Srivatsavai 	    hdr_info.mhi_dsttype != MAC_ADDRTYPE_BROADCAST) {
698b509e89bSRishi Srivatsavai 		if (hdr_info.mhi_dsttype == MAC_ADDRTYPE_UNICAST &&
699b509e89bSRishi Srivatsavai 		    bcmp(hdr_info.mhi_daddr, sdev->sd_mac_addr,
700b509e89bSRishi Srivatsavai 		    ETHERADDRL) != 0) {
701b509e89bSRishi Srivatsavai 			freemsg(mp);
7020f83d385SRishi Srivatsavai 			goto rx_done;
703b509e89bSRishi Srivatsavai 		} else if (hdr_info.mhi_dsttype == MAC_ADDRTYPE_MULTICAST) {
704b509e89bSRishi Srivatsavai 			mutex_enter(&sdev->sd_instlock);
705b509e89bSRishi Srivatsavai 			if (mcastaddr_lookup(sdev, hdr_info.mhi_daddr) ==
706b509e89bSRishi Srivatsavai 			    NULL) {
707b509e89bSRishi Srivatsavai 				mutex_exit(&sdev->sd_instlock);
708b509e89bSRishi Srivatsavai 				freemsg(mp);
7090f83d385SRishi Srivatsavai 				goto rx_done;
710b509e89bSRishi Srivatsavai 			}
711b509e89bSRishi Srivatsavai 			mutex_exit(&sdev->sd_instlock);
712b509e89bSRishi Srivatsavai 		}
713b509e89bSRishi Srivatsavai 	}
714b509e89bSRishi Srivatsavai 
715b509e89bSRishi Srivatsavai 	sdev->sd_stats.recv_count++;
716b509e89bSRishi Srivatsavai 	sdev->sd_stats.rbytes += msgdsize(mp);
717b509e89bSRishi Srivatsavai 	mac_rx(sdev->sd_mh, NULL, mp);
7180f83d385SRishi Srivatsavai rx_done:
7190f83d385SRishi Srivatsavai 	simnet_thread_unref(sdev);
720b509e89bSRishi Srivatsavai }
721b509e89bSRishi Srivatsavai 
722b509e89bSRishi Srivatsavai static mblk_t *
723b509e89bSRishi Srivatsavai simnet_m_tx(void *arg, mblk_t *mp_chain)
724b509e89bSRishi Srivatsavai {
725b509e89bSRishi Srivatsavai 	simnet_dev_t *sdev = arg;
726b509e89bSRishi Srivatsavai 	simnet_dev_t *sdev_rx;
727b509e89bSRishi Srivatsavai 	mblk_t *mpnext = mp_chain;
728b509e89bSRishi Srivatsavai 	mblk_t *mp;
729b509e89bSRishi Srivatsavai 
730b509e89bSRishi Srivatsavai 	rw_enter(&simnet_dev_lock, RW_READER);
731b509e89bSRishi Srivatsavai 	if ((sdev_rx = sdev->sd_peer_dev) == NULL) {
732b509e89bSRishi Srivatsavai 		/* Discard packets when no peer exists */
733b509e89bSRishi Srivatsavai 		rw_exit(&simnet_dev_lock);
734b509e89bSRishi Srivatsavai 		freemsgchain(mp_chain);
735b509e89bSRishi Srivatsavai 		return (NULL);
736b509e89bSRishi Srivatsavai 	}
737b509e89bSRishi Srivatsavai 
738b509e89bSRishi Srivatsavai 	/*
739b509e89bSRishi Srivatsavai 	 * Discard packets when either device is shutting down or not ready.
740b509e89bSRishi Srivatsavai 	 * Though MAC layer ensures a reference is held on the MAC while we
741b509e89bSRishi Srivatsavai 	 * process the packet chain, there is no guarantee the peer MAC will
742b509e89bSRishi Srivatsavai 	 * remain enabled. So we increment per-instance threadcount to ensure
743b509e89bSRishi Srivatsavai 	 * either MAC instance is not disabled while we handle the chain of
744b509e89bSRishi Srivatsavai 	 * packets. It is okay if the peer device is disconnected while we are
745b509e89bSRishi Srivatsavai 	 * here since we lookup the peer device while holding simnet_dev_lock
746b509e89bSRishi Srivatsavai 	 * (reader lock) and increment the threadcount of the peer, the peer
747b509e89bSRishi Srivatsavai 	 * MAC cannot be disabled in simnet_ioc_delete.
748b509e89bSRishi Srivatsavai 	 */
7490f83d385SRishi Srivatsavai 	if (!simnet_thread_ref(sdev_rx)) {
750b509e89bSRishi Srivatsavai 		rw_exit(&simnet_dev_lock);
751b509e89bSRishi Srivatsavai 		freemsgchain(mp_chain);
752b509e89bSRishi Srivatsavai 		return (NULL);
753b509e89bSRishi Srivatsavai 	}
754b509e89bSRishi Srivatsavai 	rw_exit(&simnet_dev_lock);
755b509e89bSRishi Srivatsavai 
7560f83d385SRishi Srivatsavai 	if (!simnet_thread_ref(sdev)) {
7570f83d385SRishi Srivatsavai 		simnet_thread_unref(sdev_rx);
758b509e89bSRishi Srivatsavai 		freemsgchain(mp_chain);
759b509e89bSRishi Srivatsavai 		return (NULL);
760b509e89bSRishi Srivatsavai 	}
761b509e89bSRishi Srivatsavai 
762b509e89bSRishi Srivatsavai 	while ((mp = mpnext) != NULL) {
763b509e89bSRishi Srivatsavai 		int len;
764b509e89bSRishi Srivatsavai 		int size;
765b509e89bSRishi Srivatsavai 		mblk_t *mp_new;
766b509e89bSRishi Srivatsavai 		mblk_t *mp_tmp;
767b509e89bSRishi Srivatsavai 
768b509e89bSRishi Srivatsavai 		mpnext = mp->b_next;
769b509e89bSRishi Srivatsavai 		mp->b_next = NULL;
770b509e89bSRishi Srivatsavai 		len = msgdsize(mp);
771b509e89bSRishi Srivatsavai 
772b509e89bSRishi Srivatsavai 		/* Pad packet to minimum Ethernet frame size */
773b509e89bSRishi Srivatsavai 		if (len < ETHERMIN) {
774b509e89bSRishi Srivatsavai 			size = ETHERMIN - len;
775b509e89bSRishi Srivatsavai 			mp_new = allocb(size, BPRI_HI);
776b509e89bSRishi Srivatsavai 			if (mp_new == NULL) {
777b509e89bSRishi Srivatsavai 				sdev->sd_stats.xmit_errors++;
778b509e89bSRishi Srivatsavai 				freemsg(mp);
779b509e89bSRishi Srivatsavai 				continue;
780b509e89bSRishi Srivatsavai 			}
781b509e89bSRishi Srivatsavai 			bzero(mp_new->b_wptr, size);
782b509e89bSRishi Srivatsavai 			mp_new->b_wptr += size;
783b509e89bSRishi Srivatsavai 
784b509e89bSRishi Srivatsavai 			mp_tmp = mp;
785b509e89bSRishi Srivatsavai 			while (mp_tmp->b_cont != NULL)
786b509e89bSRishi Srivatsavai 				mp_tmp = mp_tmp->b_cont;
787b509e89bSRishi Srivatsavai 			mp_tmp->b_cont = mp_new;
788b509e89bSRishi Srivatsavai 			len += size;
789b509e89bSRishi Srivatsavai 		}
790b509e89bSRishi Srivatsavai 
791b509e89bSRishi Srivatsavai 		/* Pullup packet into a single mblk */
792b509e89bSRishi Srivatsavai 		if (!pullupmsg(mp, -1)) {
793b509e89bSRishi Srivatsavai 			sdev->sd_stats.xmit_errors++;
794b509e89bSRishi Srivatsavai 			freemsg(mp);
795b509e89bSRishi Srivatsavai 			continue;
796b509e89bSRishi Srivatsavai 		}
797b509e89bSRishi Srivatsavai 
798b509e89bSRishi Srivatsavai 		/* Fix mblk checksum as the pkt dest is local */
799b509e89bSRishi Srivatsavai 		if ((mp = mac_fix_cksum(mp)) == NULL) {
800b509e89bSRishi Srivatsavai 			sdev->sd_stats.xmit_errors++;
801b509e89bSRishi Srivatsavai 			continue;
802b509e89bSRishi Srivatsavai 		}
803b509e89bSRishi Srivatsavai 
8040f83d385SRishi Srivatsavai 		/* Hold reference for taskq receive processing per-pkt */
8050f83d385SRishi Srivatsavai 		if (!simnet_thread_ref(sdev_rx)) {
8060f83d385SRishi Srivatsavai 			freemsg(mp);
8070f83d385SRishi Srivatsavai 			freemsgchain(mpnext);
8080f83d385SRishi Srivatsavai 			break;
809b509e89bSRishi Srivatsavai 		}
810b509e89bSRishi Srivatsavai 
8110f83d385SRishi Srivatsavai 		/* Use taskq for pkt receive to avoid kernel stack explosion */
8120f83d385SRishi Srivatsavai 		mp->b_next = (mblk_t *)sdev_rx;
8130f83d385SRishi Srivatsavai 		if (ddi_taskq_dispatch(simnet_rxq, simnet_rx, mp,
8140f83d385SRishi Srivatsavai 		    DDI_NOSLEEP) == DDI_SUCCESS) {
8150f83d385SRishi Srivatsavai 			sdev->sd_stats.xmit_count++;
8160f83d385SRishi Srivatsavai 			sdev->sd_stats.obytes += len;
8170f83d385SRishi Srivatsavai 		} else {
8180f83d385SRishi Srivatsavai 			simnet_thread_unref(sdev_rx);
8190f83d385SRishi Srivatsavai 			mp->b_next = NULL;
8200f83d385SRishi Srivatsavai 			freemsg(mp);
8210f83d385SRishi Srivatsavai 			sdev_rx->sd_stats.recv_errors++;
8220f83d385SRishi Srivatsavai 		}
8230f83d385SRishi Srivatsavai 	}
8240f83d385SRishi Srivatsavai 
8250f83d385SRishi Srivatsavai 	simnet_thread_unref(sdev);
8260f83d385SRishi Srivatsavai 	simnet_thread_unref(sdev_rx);
827b509e89bSRishi Srivatsavai 	return (NULL);
828b509e89bSRishi Srivatsavai }
829b509e89bSRishi Srivatsavai 
830b509e89bSRishi Srivatsavai static int
831b509e89bSRishi Srivatsavai simnet_wifi_ioctl(simnet_dev_t *sdev, mblk_t *mp)
832b509e89bSRishi Srivatsavai {
833b509e89bSRishi Srivatsavai 	int rc = WL_SUCCESS;
834b509e89bSRishi Srivatsavai 	simnet_wifidev_t *wdev = sdev->sd_wifidev;
835b509e89bSRishi Srivatsavai 
836b509e89bSRishi Srivatsavai 	/* LINTED E_BAD_PTR_CAST_ALIGN */
837b509e89bSRishi Srivatsavai 	switch (((wldp_t *)mp->b_rptr)->wldp_id) {
838b509e89bSRishi Srivatsavai 	case WL_DISASSOCIATE:
839b509e89bSRishi Srivatsavai 		wdev->swd_linkstatus = WL_NOTCONNECTED;
840b509e89bSRishi Srivatsavai 		break;
841b509e89bSRishi Srivatsavai 	default:
842b509e89bSRishi Srivatsavai 		break;
843b509e89bSRishi Srivatsavai 	}
844b509e89bSRishi Srivatsavai 	return (rc);
845b509e89bSRishi Srivatsavai }
846b509e89bSRishi Srivatsavai 
847b509e89bSRishi Srivatsavai static void
848b509e89bSRishi Srivatsavai simnet_m_ioctl(void *arg, queue_t *q, mblk_t *mp)
849b509e89bSRishi Srivatsavai {
850b509e89bSRishi Srivatsavai 	simnet_dev_t *sdev = arg;
851b509e89bSRishi Srivatsavai 	struct	iocblk	*iocp;
852b509e89bSRishi Srivatsavai 	mblk_t	*mp1;
853b509e89bSRishi Srivatsavai 	uint32_t cmd;
854b509e89bSRishi Srivatsavai 	int rc;
855b509e89bSRishi Srivatsavai 
856b509e89bSRishi Srivatsavai 	if (sdev->sd_type != DL_WIFI) {
857b509e89bSRishi Srivatsavai 		miocnak(q, mp, 0, ENOTSUP);
858b509e89bSRishi Srivatsavai 		return;
859b509e89bSRishi Srivatsavai 	}
860b509e89bSRishi Srivatsavai 
861b509e89bSRishi Srivatsavai 	/* LINTED E_BAD_PTR_CAST_ALIGN */
862b509e89bSRishi Srivatsavai 	iocp = (struct iocblk *)mp->b_rptr;
863b509e89bSRishi Srivatsavai 	if (iocp->ioc_count == 0) {
864b509e89bSRishi Srivatsavai 		miocnak(q, mp, 0, EINVAL);
865b509e89bSRishi Srivatsavai 		return;
866b509e89bSRishi Srivatsavai 	}
867b509e89bSRishi Srivatsavai 
868b509e89bSRishi Srivatsavai 	/* We only claim support for WiFi operation commands */
869b509e89bSRishi Srivatsavai 	cmd = iocp->ioc_cmd;
870b509e89bSRishi Srivatsavai 	switch (cmd) {
871b509e89bSRishi Srivatsavai 	default:
872b509e89bSRishi Srivatsavai 		miocnak(q, mp, 0, EINVAL);
873b509e89bSRishi Srivatsavai 		return;
874b509e89bSRishi Srivatsavai 	case WLAN_GET_PARAM:
875b509e89bSRishi Srivatsavai 	case WLAN_SET_PARAM:
876b509e89bSRishi Srivatsavai 	case WLAN_COMMAND:
877b509e89bSRishi Srivatsavai 		break;
878b509e89bSRishi Srivatsavai 	}
879b509e89bSRishi Srivatsavai 
880b509e89bSRishi Srivatsavai 	mp1 = mp->b_cont;
881b509e89bSRishi Srivatsavai 	freemsg(mp1->b_cont);
882b509e89bSRishi Srivatsavai 	mp1->b_cont = NULL;
883b509e89bSRishi Srivatsavai 	/* overwrite everything */
884b509e89bSRishi Srivatsavai 	mp1->b_wptr = mp1->b_rptr;
885b509e89bSRishi Srivatsavai 	rc = simnet_wifi_ioctl(sdev, mp1);
886b509e89bSRishi Srivatsavai 	miocack(q, mp, msgdsize(mp1), rc);
887b509e89bSRishi Srivatsavai }
888b509e89bSRishi Srivatsavai 
889b509e89bSRishi Srivatsavai static int
890b509e89bSRishi Srivatsavai simnet_m_stat(void *arg, uint_t stat, uint64_t *val)
891b509e89bSRishi Srivatsavai {
892b509e89bSRishi Srivatsavai 	int rval = 0;
893b509e89bSRishi Srivatsavai 	simnet_dev_t *sdev = arg;
894b509e89bSRishi Srivatsavai 
895b509e89bSRishi Srivatsavai 	ASSERT(sdev->sd_mh != NULL);
896b509e89bSRishi Srivatsavai 
897b509e89bSRishi Srivatsavai 	switch (stat) {
898b509e89bSRishi Srivatsavai 	case MAC_STAT_IFSPEED:
899b509e89bSRishi Srivatsavai 		*val = 100 * 1000000ull; /* 100 Mbps */
900b509e89bSRishi Srivatsavai 		break;
901b509e89bSRishi Srivatsavai 	case MAC_STAT_LINK_STATE:
902b509e89bSRishi Srivatsavai 		*val = LINK_DUPLEX_FULL;
903b509e89bSRishi Srivatsavai 		break;
904b509e89bSRishi Srivatsavai 	case MAC_STAT_LINK_UP:
905b509e89bSRishi Srivatsavai 		if (sdev->sd_flags & SDF_STARTED)
906b509e89bSRishi Srivatsavai 			*val = LINK_STATE_UP;
907b509e89bSRishi Srivatsavai 		else
908b509e89bSRishi Srivatsavai 			*val = LINK_STATE_DOWN;
909b509e89bSRishi Srivatsavai 		break;
910b509e89bSRishi Srivatsavai 	case MAC_STAT_PROMISC:
911b509e89bSRishi Srivatsavai 	case MAC_STAT_MULTIRCV:
912b509e89bSRishi Srivatsavai 	case MAC_STAT_MULTIXMT:
913b509e89bSRishi Srivatsavai 	case MAC_STAT_BRDCSTRCV:
914b509e89bSRishi Srivatsavai 	case MAC_STAT_BRDCSTXMT:
915b509e89bSRishi Srivatsavai 		rval = ENOTSUP;
916b509e89bSRishi Srivatsavai 		break;
917b509e89bSRishi Srivatsavai 	case MAC_STAT_OPACKETS:
918b509e89bSRishi Srivatsavai 		*val = sdev->sd_stats.xmit_count;
919b509e89bSRishi Srivatsavai 		break;
920b509e89bSRishi Srivatsavai 	case MAC_STAT_OBYTES:
921b509e89bSRishi Srivatsavai 		*val = sdev->sd_stats.obytes;
922b509e89bSRishi Srivatsavai 		break;
923b509e89bSRishi Srivatsavai 	case MAC_STAT_IERRORS:
924b509e89bSRishi Srivatsavai 		*val = sdev->sd_stats.recv_errors;
925b509e89bSRishi Srivatsavai 		break;
926b509e89bSRishi Srivatsavai 	case MAC_STAT_OERRORS:
927b509e89bSRishi Srivatsavai 		*val = sdev->sd_stats.xmit_errors;
928b509e89bSRishi Srivatsavai 		break;
929b509e89bSRishi Srivatsavai 	case MAC_STAT_RBYTES:
930b509e89bSRishi Srivatsavai 		*val = sdev->sd_stats.rbytes;
931b509e89bSRishi Srivatsavai 		break;
932b509e89bSRishi Srivatsavai 	case MAC_STAT_IPACKETS:
933b509e89bSRishi Srivatsavai 		*val = sdev->sd_stats.recv_count;
934b509e89bSRishi Srivatsavai 		break;
935b509e89bSRishi Srivatsavai 	case WIFI_STAT_FCS_ERRORS:
936b509e89bSRishi Srivatsavai 	case WIFI_STAT_WEP_ERRORS:
937b509e89bSRishi Srivatsavai 	case WIFI_STAT_TX_FRAGS:
938b509e89bSRishi Srivatsavai 	case WIFI_STAT_MCAST_TX:
939b509e89bSRishi Srivatsavai 	case WIFI_STAT_RTS_SUCCESS:
940b509e89bSRishi Srivatsavai 	case WIFI_STAT_RTS_FAILURE:
941b509e89bSRishi Srivatsavai 	case WIFI_STAT_ACK_FAILURE:
942b509e89bSRishi Srivatsavai 	case WIFI_STAT_RX_FRAGS:
943b509e89bSRishi Srivatsavai 	case WIFI_STAT_MCAST_RX:
944b509e89bSRishi Srivatsavai 	case WIFI_STAT_RX_DUPS:
945b509e89bSRishi Srivatsavai 		rval = ENOTSUP;
946b509e89bSRishi Srivatsavai 		break;
947b509e89bSRishi Srivatsavai 	default:
948b509e89bSRishi Srivatsavai 		rval = ENOTSUP;
949b509e89bSRishi Srivatsavai 		break;
950b509e89bSRishi Srivatsavai 	}
951b509e89bSRishi Srivatsavai 
952b509e89bSRishi Srivatsavai 	return (rval);
953b509e89bSRishi Srivatsavai }
954b509e89bSRishi Srivatsavai 
955b509e89bSRishi Srivatsavai static int
956b509e89bSRishi Srivatsavai simnet_m_start(void *arg)
957b509e89bSRishi Srivatsavai {
958b509e89bSRishi Srivatsavai 	simnet_dev_t *sdev = arg;
959b509e89bSRishi Srivatsavai 
960b509e89bSRishi Srivatsavai 	sdev->sd_flags |= SDF_STARTED;
961b509e89bSRishi Srivatsavai 	return (0);
962b509e89bSRishi Srivatsavai }
963b509e89bSRishi Srivatsavai 
964b509e89bSRishi Srivatsavai static void
965b509e89bSRishi Srivatsavai simnet_m_stop(void *arg)
966b509e89bSRishi Srivatsavai {
967b509e89bSRishi Srivatsavai 	simnet_dev_t *sdev = arg;
968b509e89bSRishi Srivatsavai 
969b509e89bSRishi Srivatsavai 	sdev->sd_flags &= ~SDF_STARTED;
970b509e89bSRishi Srivatsavai }
971b509e89bSRishi Srivatsavai 
972b509e89bSRishi Srivatsavai static int
973b509e89bSRishi Srivatsavai simnet_m_promisc(void *arg, boolean_t on)
974b509e89bSRishi Srivatsavai {
975b509e89bSRishi Srivatsavai 	simnet_dev_t *sdev = arg;
976b509e89bSRishi Srivatsavai 
977b509e89bSRishi Srivatsavai 	sdev->sd_promisc = on;
978b509e89bSRishi Srivatsavai 	return (0);
979b509e89bSRishi Srivatsavai }
980b509e89bSRishi Srivatsavai 
981b509e89bSRishi Srivatsavai /*
982b509e89bSRishi Srivatsavai  * Returns matching multicast address enabled on the simnet instance.
983b509e89bSRishi Srivatsavai  * Assumes simnet instance mutex lock is held.
984b509e89bSRishi Srivatsavai  */
985b509e89bSRishi Srivatsavai static uint8_t *
986b509e89bSRishi Srivatsavai mcastaddr_lookup(simnet_dev_t *sdev, const uint8_t *addrp)
987b509e89bSRishi Srivatsavai {
988b509e89bSRishi Srivatsavai 	int idx;
989b509e89bSRishi Srivatsavai 	uint8_t *maddrptr;
990b509e89bSRishi Srivatsavai 
9910f83d385SRishi Srivatsavai 	ASSERT(MUTEX_HELD(&sdev->sd_instlock));
992b509e89bSRishi Srivatsavai 	maddrptr = sdev->sd_mcastaddrs;
993b509e89bSRishi Srivatsavai 	for (idx = 0; idx < sdev->sd_mcastaddr_count; idx++) {
994b509e89bSRishi Srivatsavai 		if (bcmp(maddrptr, addrp, ETHERADDRL) == 0)
995b509e89bSRishi Srivatsavai 			return (maddrptr);
996b509e89bSRishi Srivatsavai 		maddrptr += ETHERADDRL;
997b509e89bSRishi Srivatsavai 	}
998b509e89bSRishi Srivatsavai 
999b509e89bSRishi Srivatsavai 	return (NULL);
1000b509e89bSRishi Srivatsavai }
1001b509e89bSRishi Srivatsavai 
1002b509e89bSRishi Srivatsavai /* Add or remove Multicast addresses on simnet instance */
1003b509e89bSRishi Srivatsavai static int
1004b509e89bSRishi Srivatsavai simnet_m_multicst(void *arg, boolean_t add, const uint8_t *addrp)
1005b509e89bSRishi Srivatsavai {
1006b509e89bSRishi Srivatsavai 	simnet_dev_t *sdev = arg;
1007b509e89bSRishi Srivatsavai 	uint8_t *maddrptr;
1008b509e89bSRishi Srivatsavai 	uint8_t *newbuf;
1009b509e89bSRishi Srivatsavai 	size_t prevsize;
1010b509e89bSRishi Srivatsavai 	size_t newsize;
1011b509e89bSRishi Srivatsavai 	ptrdiff_t len;
1012b509e89bSRishi Srivatsavai 	ptrdiff_t len2;
1013b509e89bSRishi Srivatsavai 
1014b509e89bSRishi Srivatsavai alloc_retry:
1015b509e89bSRishi Srivatsavai 	prevsize = sdev->sd_mcastaddr_count * ETHERADDRL;
1016b509e89bSRishi Srivatsavai 	newsize = prevsize + (add ? ETHERADDRL:-ETHERADDRL);
1017b509e89bSRishi Srivatsavai 	newbuf = kmem_alloc(newsize, KM_SLEEP);
1018b509e89bSRishi Srivatsavai 
1019b509e89bSRishi Srivatsavai 	mutex_enter(&sdev->sd_instlock);
1020b509e89bSRishi Srivatsavai 	if (prevsize != (sdev->sd_mcastaddr_count * ETHERADDRL)) {
1021b509e89bSRishi Srivatsavai 		mutex_exit(&sdev->sd_instlock);
1022b509e89bSRishi Srivatsavai 		kmem_free(newbuf, newsize);
1023b509e89bSRishi Srivatsavai 		goto alloc_retry;
1024b509e89bSRishi Srivatsavai 	}
1025b509e89bSRishi Srivatsavai 
1026b509e89bSRishi Srivatsavai 	maddrptr = mcastaddr_lookup(sdev, addrp);
1027b509e89bSRishi Srivatsavai 	if (!add && maddrptr != NULL) {
1028b509e89bSRishi Srivatsavai 		/* Removing a Multicast address */
1029b509e89bSRishi Srivatsavai 		if (newbuf != NULL) {
1030b509e89bSRishi Srivatsavai 			/* LINTED: E_PTRDIFF_OVERFLOW */
1031b509e89bSRishi Srivatsavai 			len = maddrptr - sdev->sd_mcastaddrs;
1032b509e89bSRishi Srivatsavai 			(void) memcpy(newbuf, sdev->sd_mcastaddrs, len);
1033b509e89bSRishi Srivatsavai 			len2 = prevsize - len - ETHERADDRL;
1034b509e89bSRishi Srivatsavai 			(void) memcpy(newbuf + len,
1035b509e89bSRishi Srivatsavai 			    maddrptr + ETHERADDRL, len2);
1036b509e89bSRishi Srivatsavai 		}
1037b509e89bSRishi Srivatsavai 		sdev->sd_mcastaddr_count--;
1038b509e89bSRishi Srivatsavai 	} else if (add && maddrptr == NULL) {
1039b509e89bSRishi Srivatsavai 		/* Adding a new Multicast address */
1040b509e89bSRishi Srivatsavai 		(void) memcpy(newbuf, sdev->sd_mcastaddrs, prevsize);
1041b509e89bSRishi Srivatsavai 		(void) memcpy(newbuf + prevsize, addrp, ETHERADDRL);
1042b509e89bSRishi Srivatsavai 		sdev->sd_mcastaddr_count++;
1043b509e89bSRishi Srivatsavai 	} else {
1044b509e89bSRishi Srivatsavai 		/* Error: removing a non-existing Multicast address */
1045b509e89bSRishi Srivatsavai 		mutex_exit(&sdev->sd_instlock);
1046b509e89bSRishi Srivatsavai 		kmem_free(newbuf, newsize);
1047b509e89bSRishi Srivatsavai 		cmn_err(CE_WARN, "simnet: MAC call to remove a "
1048b509e89bSRishi Srivatsavai 		    "Multicast address failed");
1049b509e89bSRishi Srivatsavai 		return (EINVAL);
1050b509e89bSRishi Srivatsavai 	}
1051b509e89bSRishi Srivatsavai 
1052b509e89bSRishi Srivatsavai 	kmem_free(sdev->sd_mcastaddrs, prevsize);
1053b509e89bSRishi Srivatsavai 	sdev->sd_mcastaddrs = newbuf;
1054b509e89bSRishi Srivatsavai 	mutex_exit(&sdev->sd_instlock);
1055b509e89bSRishi Srivatsavai 	return (0);
1056b509e89bSRishi Srivatsavai }
1057b509e89bSRishi Srivatsavai 
1058b509e89bSRishi Srivatsavai static int
1059b509e89bSRishi Srivatsavai simnet_m_unicst(void *arg, const uint8_t *macaddr)
1060b509e89bSRishi Srivatsavai {
1061b509e89bSRishi Srivatsavai 	simnet_dev_t *sdev = arg;
1062b509e89bSRishi Srivatsavai 
1063b509e89bSRishi Srivatsavai 	(void) memcpy(sdev->sd_mac_addr, macaddr, ETHERADDRL);
1064b509e89bSRishi Srivatsavai 	return (0);
1065b509e89bSRishi Srivatsavai }
1066b509e89bSRishi Srivatsavai 
1067b509e89bSRishi Srivatsavai /* Parse WiFi scan list entry arguments and return the arg count */
1068b509e89bSRishi Srivatsavai static int
1069b509e89bSRishi Srivatsavai parse_esslist_args(const void *pr_val, uint_t pr_valsize,
1070b509e89bSRishi Srivatsavai     char args[][MAX_ESSLIST_ARGLEN])
1071b509e89bSRishi Srivatsavai {
1072b509e89bSRishi Srivatsavai 	char *sep;
1073b509e89bSRishi Srivatsavai 	ptrdiff_t len = pr_valsize;
1074b509e89bSRishi Srivatsavai 	const char *piece = pr_val;
1075b509e89bSRishi Srivatsavai 	const char *end = (const char *)pr_val + pr_valsize - 1;
1076b509e89bSRishi Srivatsavai 	int arg = 0;
1077b509e89bSRishi Srivatsavai 
1078b509e89bSRishi Srivatsavai 	while (piece < end && (arg < MAX_ESSLIST_ARGS)) {
1079b509e89bSRishi Srivatsavai 		sep = strchr(piece, ',');
1080b509e89bSRishi Srivatsavai 		if (sep == NULL)
1081b509e89bSRishi Srivatsavai 			sep = (char *)end;
1082b509e89bSRishi Srivatsavai 		/* LINTED E_PTRDIFF_OVERFLOW */
1083b509e89bSRishi Srivatsavai 		len = sep - piece;
1084b509e89bSRishi Srivatsavai 		/* If first arg is zero then return none to delete all */
1085b509e89bSRishi Srivatsavai 		if (arg == 0 && strnlen(piece, len) == 1 && piece[0] == '0')
1086b509e89bSRishi Srivatsavai 			return (0);
1087b509e89bSRishi Srivatsavai 		if (len > MAX_ESSLIST_ARGLEN)
1088b509e89bSRishi Srivatsavai 			len = MAX_ESSLIST_ARGLEN - 1;
1089b509e89bSRishi Srivatsavai 		(void) memcpy(&args[arg][0], piece, len);
1090b509e89bSRishi Srivatsavai 		args[arg][len] = '\0';
1091b509e89bSRishi Srivatsavai 		piece = sep + 1;
1092b509e89bSRishi Srivatsavai 		arg++;
1093b509e89bSRishi Srivatsavai 	}
1094b509e89bSRishi Srivatsavai 
1095b509e89bSRishi Srivatsavai 	return (arg);
1096b509e89bSRishi Srivatsavai }
1097b509e89bSRishi Srivatsavai 
1098b509e89bSRishi Srivatsavai /* Set WiFi scan list entry from private property _wl_esslist */
1099b509e89bSRishi Srivatsavai static int
1100b509e89bSRishi Srivatsavai set_wl_esslist_priv_prop(simnet_wifidev_t *wdev, uint_t pr_valsize,
1101b509e89bSRishi Srivatsavai     const void *pr_val)
1102b509e89bSRishi Srivatsavai {
1103b509e89bSRishi Srivatsavai 	char essargs[MAX_ESSLIST_ARGS][MAX_ESSLIST_ARGLEN];
1104b509e89bSRishi Srivatsavai 	wl_ess_conf_t *wls;
1105b509e89bSRishi Srivatsavai 	long result;
1106b509e89bSRishi Srivatsavai 	int i;
1107b509e89bSRishi Srivatsavai 
1108b509e89bSRishi Srivatsavai 	bzero(essargs, sizeof (essargs));
1109b509e89bSRishi Srivatsavai 	if (parse_esslist_args(pr_val, pr_valsize, essargs) == 0) {
1110b509e89bSRishi Srivatsavai 		for (i = 0; i < wdev->swd_esslist_num; i++) {
1111b509e89bSRishi Srivatsavai 			kmem_free(wdev->swd_esslist[i], sizeof (wl_ess_conf_t));
1112b509e89bSRishi Srivatsavai 			wdev->swd_esslist[i] = NULL;
1113b509e89bSRishi Srivatsavai 		}
1114b509e89bSRishi Srivatsavai 		wdev->swd_esslist_num = 0;
1115b509e89bSRishi Srivatsavai 		return (0);
1116b509e89bSRishi Srivatsavai 	}
1117b509e89bSRishi Srivatsavai 
1118b509e89bSRishi Srivatsavai 	for (i = 0; i < wdev->swd_esslist_num; i++) {
1119b509e89bSRishi Srivatsavai 		wls = wdev->swd_esslist[i];
1120b509e89bSRishi Srivatsavai 		if (strcasecmp(wls->wl_ess_conf_essid.wl_essid_essid,
1121b509e89bSRishi Srivatsavai 		    essargs[0]) == 0)
1122b509e89bSRishi Srivatsavai 			return (EEXIST);
1123b509e89bSRishi Srivatsavai 	}
1124b509e89bSRishi Srivatsavai 
1125b509e89bSRishi Srivatsavai 	if (wdev->swd_esslist_num >= MAX_SIMNET_ESSCONF)
1126b509e89bSRishi Srivatsavai 		return (EINVAL);
1127b509e89bSRishi Srivatsavai 
1128b509e89bSRishi Srivatsavai 	wls = kmem_zalloc(sizeof (wl_ess_conf_t), KM_SLEEP);
1129b509e89bSRishi Srivatsavai 	(void) strlcpy(wls->wl_ess_conf_essid.wl_essid_essid,
1130b509e89bSRishi Srivatsavai 	    essargs[0], sizeof (wls->wl_ess_conf_essid.wl_essid_essid));
1131b509e89bSRishi Srivatsavai 	wls->wl_ess_conf_essid.wl_essid_length =
1132b509e89bSRishi Srivatsavai 	    strlen(wls->wl_ess_conf_essid.wl_essid_essid);
1133b509e89bSRishi Srivatsavai 	(void) random_get_pseudo_bytes((uint8_t *)
1134b509e89bSRishi Srivatsavai 	    &wls->wl_ess_conf_bssid, sizeof (wl_bssid_t));
1135b509e89bSRishi Srivatsavai 	(void) ddi_strtol(essargs[1], (char **)NULL, 0, &result);
1136b509e89bSRishi Srivatsavai 	wls->wl_ess_conf_sl = (wl_rssi_t)
1137b509e89bSRishi Srivatsavai 	    ((result > MAX_RSSI || result < 0) ? 0:result);
1138b509e89bSRishi Srivatsavai 	wdev->swd_esslist[wdev->swd_esslist_num] = wls;
1139b509e89bSRishi Srivatsavai 	wdev->swd_esslist_num++;
1140b509e89bSRishi Srivatsavai 
1141b509e89bSRishi Srivatsavai 	return (0);
1142b509e89bSRishi Srivatsavai }
1143b509e89bSRishi Srivatsavai 
1144b509e89bSRishi Srivatsavai static int
1145b509e89bSRishi Srivatsavai simnet_set_priv_prop(simnet_dev_t *sdev, const char *pr_name,
1146b509e89bSRishi Srivatsavai     uint_t pr_valsize, const void *pr_val)
1147b509e89bSRishi Srivatsavai {
1148b509e89bSRishi Srivatsavai 	simnet_wifidev_t *wdev = sdev->sd_wifidev;
1149b509e89bSRishi Srivatsavai 	long result;
1150b509e89bSRishi Srivatsavai 
1151b509e89bSRishi Srivatsavai 	if (strcmp(pr_name, "_wl_esslist") == 0) {
1152b509e89bSRishi Srivatsavai 		if (pr_val == NULL)
1153b509e89bSRishi Srivatsavai 			return (EINVAL);
1154b509e89bSRishi Srivatsavai 		return (set_wl_esslist_priv_prop(wdev, pr_valsize, pr_val));
1155b509e89bSRishi Srivatsavai 	} else if (strcmp(pr_name, "_wl_connected") == 0) {
1156b509e89bSRishi Srivatsavai 		if (pr_val == NULL)
1157b509e89bSRishi Srivatsavai 			return (EINVAL);
1158b509e89bSRishi Srivatsavai 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
1159b509e89bSRishi Srivatsavai 		wdev->swd_linkstatus = ((result == 1) ?
1160b509e89bSRishi Srivatsavai 		    WL_CONNECTED:WL_NOTCONNECTED);
1161b509e89bSRishi Srivatsavai 		return (0);
1162b509e89bSRishi Srivatsavai 	}
1163b509e89bSRishi Srivatsavai 
1164b509e89bSRishi Srivatsavai 	return (EINVAL);
1165b509e89bSRishi Srivatsavai }
1166b509e89bSRishi Srivatsavai 
1167b509e89bSRishi Srivatsavai static int
1168b509e89bSRishi Srivatsavai simnet_m_setprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
1169b509e89bSRishi Srivatsavai     uint_t wldp_length, const void *wldp_buf)
1170b509e89bSRishi Srivatsavai {
1171b509e89bSRishi Srivatsavai 	simnet_dev_t *sdev = arg;
1172b509e89bSRishi Srivatsavai 	simnet_wifidev_t *wdev = sdev->sd_wifidev;
1173b509e89bSRishi Srivatsavai 	int err = 0;
1174b509e89bSRishi Srivatsavai 	uint32_t mtu;
1175b509e89bSRishi Srivatsavai 
1176b509e89bSRishi Srivatsavai 	switch (wldp_pr_num) {
1177b509e89bSRishi Srivatsavai 	case MAC_PROP_MTU:
1178b509e89bSRishi Srivatsavai 		(void) memcpy(&mtu, wldp_buf, sizeof (mtu));
1179b509e89bSRishi Srivatsavai 		if (mtu > ETHERMIN && mtu < SIMNET_MAX_MTU)
1180b509e89bSRishi Srivatsavai 			return (mac_maxsdu_update(sdev->sd_mh, mtu));
1181b509e89bSRishi Srivatsavai 		else
1182b509e89bSRishi Srivatsavai 			return (EINVAL);
1183b509e89bSRishi Srivatsavai 	default:
1184b509e89bSRishi Srivatsavai 		break;
1185b509e89bSRishi Srivatsavai 	}
1186b509e89bSRishi Srivatsavai 
1187b509e89bSRishi Srivatsavai 	if (sdev->sd_type == DL_ETHER)
1188b509e89bSRishi Srivatsavai 		return (ENOTSUP);
1189b509e89bSRishi Srivatsavai 
1190b509e89bSRishi Srivatsavai 	/* mac_prop_id */
1191b509e89bSRishi Srivatsavai 	switch (wldp_pr_num) {
1192b509e89bSRishi Srivatsavai 	case MAC_PROP_WL_ESSID: {
1193b509e89bSRishi Srivatsavai 		int i;
1194b509e89bSRishi Srivatsavai 		wl_ess_conf_t *wls;
1195b509e89bSRishi Srivatsavai 
1196b509e89bSRishi Srivatsavai 		(void) memcpy(&wdev->swd_essid, wldp_buf,
1197b509e89bSRishi Srivatsavai 		    sizeof (wl_essid_t));
1198b509e89bSRishi Srivatsavai 		wdev->swd_linkstatus = WL_CONNECTED;
1199b509e89bSRishi Srivatsavai 
1200b509e89bSRishi Srivatsavai 		/* Lookup the signal strength of the connected ESSID */
1201b509e89bSRishi Srivatsavai 		for (i = 0; i < wdev->swd_esslist_num; i++) {
1202b509e89bSRishi Srivatsavai 			wls = wdev->swd_esslist[i];
1203b509e89bSRishi Srivatsavai 			if (strcasecmp(wls->wl_ess_conf_essid.wl_essid_essid,
1204b509e89bSRishi Srivatsavai 			    wdev->swd_essid.wl_essid_essid) == 0) {
1205b509e89bSRishi Srivatsavai 				wdev->swd_rssi = wls->wl_ess_conf_sl;
1206b509e89bSRishi Srivatsavai 				break;
1207b509e89bSRishi Srivatsavai 			}
1208b509e89bSRishi Srivatsavai 		}
1209b509e89bSRishi Srivatsavai 		break;
1210b509e89bSRishi Srivatsavai 	}
1211b509e89bSRishi Srivatsavai 	case MAC_PROP_WL_BSSID: {
1212b509e89bSRishi Srivatsavai 		(void) memcpy(&wdev->swd_bssid, wldp_buf,
1213b509e89bSRishi Srivatsavai 		    sizeof (wl_bssid_t));
1214b509e89bSRishi Srivatsavai 		break;
1215b509e89bSRishi Srivatsavai 	}
1216b509e89bSRishi Srivatsavai 	case MAC_PROP_WL_PHY_CONFIG:
1217b509e89bSRishi Srivatsavai 	case MAC_PROP_WL_KEY_TAB:
1218b509e89bSRishi Srivatsavai 	case MAC_PROP_WL_AUTH_MODE:
1219b509e89bSRishi Srivatsavai 	case MAC_PROP_WL_ENCRYPTION:
1220b509e89bSRishi Srivatsavai 	case MAC_PROP_WL_BSSTYPE:
1221b509e89bSRishi Srivatsavai 	case MAC_PROP_WL_DESIRED_RATES:
1222b509e89bSRishi Srivatsavai 		break;
1223b509e89bSRishi Srivatsavai 	case MAC_PROP_PRIVATE:
1224b509e89bSRishi Srivatsavai 		err = simnet_set_priv_prop(sdev, pr_name,
1225b509e89bSRishi Srivatsavai 		    wldp_length, wldp_buf);
1226b509e89bSRishi Srivatsavai 		break;
1227b509e89bSRishi Srivatsavai 	default:
1228b509e89bSRishi Srivatsavai 		break;
1229b509e89bSRishi Srivatsavai 	}
1230b509e89bSRishi Srivatsavai 
1231b509e89bSRishi Srivatsavai 	return (err);
1232b509e89bSRishi Srivatsavai }
1233b509e89bSRishi Srivatsavai 
1234b509e89bSRishi Srivatsavai static int
1235*0dc2366fSVenugopal Iyer simnet_get_priv_prop(simnet_dev_t *sdev, const char *pr_name,
1236b509e89bSRishi Srivatsavai     uint_t pr_valsize, void *pr_val)
1237b509e89bSRishi Srivatsavai {
1238b509e89bSRishi Srivatsavai 	simnet_wifidev_t *wdev = sdev->sd_wifidev;
1239b509e89bSRishi Srivatsavai 	int err = 0;
1240b509e89bSRishi Srivatsavai 	int value;
1241b509e89bSRishi Srivatsavai 
1242b509e89bSRishi Srivatsavai 	if (strcmp(pr_name, "_wl_esslist") == 0) {
1243b509e89bSRishi Srivatsavai 		/* Returns num of _wl_ess_conf_t that have been set */
1244*0dc2366fSVenugopal Iyer 		value = wdev->swd_esslist_num;
1245b509e89bSRishi Srivatsavai 	} else if (strcmp(pr_name, "_wl_connected") == 0) {
1246b509e89bSRishi Srivatsavai 		value = ((wdev->swd_linkstatus == WL_CONNECTED) ? 1:0);
1247b509e89bSRishi Srivatsavai 	} else {
1248b509e89bSRishi Srivatsavai 		err = ENOTSUP;
1249b509e89bSRishi Srivatsavai 	}
1250b509e89bSRishi Srivatsavai 
1251b509e89bSRishi Srivatsavai 	if (err == 0)
1252b509e89bSRishi Srivatsavai 		(void) snprintf(pr_val, pr_valsize, "%d", value);
1253b509e89bSRishi Srivatsavai 	return (err);
1254b509e89bSRishi Srivatsavai }
1255b509e89bSRishi Srivatsavai 
1256b509e89bSRishi Srivatsavai static int
1257b509e89bSRishi Srivatsavai simnet_m_getprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
1258*0dc2366fSVenugopal Iyer     uint_t wldp_length, void *wldp_buf)
1259b509e89bSRishi Srivatsavai {
1260b509e89bSRishi Srivatsavai 	simnet_dev_t *sdev = arg;
1261b509e89bSRishi Srivatsavai 	simnet_wifidev_t *wdev = sdev->sd_wifidev;
1262b509e89bSRishi Srivatsavai 	int err = 0;
1263b509e89bSRishi Srivatsavai 	int i;
1264b509e89bSRishi Srivatsavai 
1265b509e89bSRishi Srivatsavai 	if (sdev->sd_type == DL_ETHER)
1266b509e89bSRishi Srivatsavai 		return (ENOTSUP);
1267b509e89bSRishi Srivatsavai 
1268b509e89bSRishi Srivatsavai 	/* mac_prop_id */
1269b509e89bSRishi Srivatsavai 	switch (wldp_pr_num) {
1270b509e89bSRishi Srivatsavai 	case MAC_PROP_WL_ESSID:
1271b509e89bSRishi Srivatsavai 		(void) memcpy(wldp_buf, &wdev->swd_essid,
1272b509e89bSRishi Srivatsavai 		    sizeof (wl_essid_t));
1273b509e89bSRishi Srivatsavai 		break;
1274b509e89bSRishi Srivatsavai 	case MAC_PROP_WL_BSSID:
1275b509e89bSRishi Srivatsavai 		(void) memcpy(wldp_buf, &wdev->swd_bssid,
1276b509e89bSRishi Srivatsavai 		    sizeof (wl_bssid_t));
1277b509e89bSRishi Srivatsavai 		break;
1278b509e89bSRishi Srivatsavai 	case MAC_PROP_WL_PHY_CONFIG:
1279b509e89bSRishi Srivatsavai 	case MAC_PROP_WL_AUTH_MODE:
1280b509e89bSRishi Srivatsavai 	case MAC_PROP_WL_ENCRYPTION:
1281b509e89bSRishi Srivatsavai 		break;
1282b509e89bSRishi Srivatsavai 	case MAC_PROP_WL_LINKSTATUS:
1283b509e89bSRishi Srivatsavai 		(void) memcpy(wldp_buf, &wdev->swd_linkstatus,
1284b509e89bSRishi Srivatsavai 		    sizeof (wdev->swd_linkstatus));
1285b509e89bSRishi Srivatsavai 		break;
1286b509e89bSRishi Srivatsavai 	case MAC_PROP_WL_ESS_LIST: {
1287b509e89bSRishi Srivatsavai 		wl_ess_conf_t *w_ess_conf;
1288b509e89bSRishi Srivatsavai 
1289b509e89bSRishi Srivatsavai 		((wl_ess_list_t *)wldp_buf)->wl_ess_list_num =
1290b509e89bSRishi Srivatsavai 		    wdev->swd_esslist_num;
1291b509e89bSRishi Srivatsavai 		/* LINTED E_BAD_PTR_CAST_ALIGN */
1292b509e89bSRishi Srivatsavai 		w_ess_conf = (wl_ess_conf_t *)((char *)wldp_buf +
1293b509e89bSRishi Srivatsavai 		    offsetof(wl_ess_list_t, wl_ess_list_ess));
1294b509e89bSRishi Srivatsavai 		for (i = 0; i < wdev->swd_esslist_num; i++) {
1295b509e89bSRishi Srivatsavai 			(void) memcpy(w_ess_conf, wdev->swd_esslist[i],
1296b509e89bSRishi Srivatsavai 			    sizeof (wl_ess_conf_t));
1297b509e89bSRishi Srivatsavai 			w_ess_conf++;
1298b509e89bSRishi Srivatsavai 		}
1299b509e89bSRishi Srivatsavai 		break;
1300b509e89bSRishi Srivatsavai 	}
1301b509e89bSRishi Srivatsavai 	case MAC_PROP_WL_RSSI:
1302b509e89bSRishi Srivatsavai 		*(wl_rssi_t *)wldp_buf = wdev->swd_rssi;
1303b509e89bSRishi Srivatsavai 		break;
1304b509e89bSRishi Srivatsavai 	case MAC_PROP_WL_RADIO:
1305b509e89bSRishi Srivatsavai 		*(wl_radio_t *)wldp_buf = B_TRUE;
1306b509e89bSRishi Srivatsavai 		break;
1307b509e89bSRishi Srivatsavai 	case MAC_PROP_WL_POWER_MODE:
1308b509e89bSRishi Srivatsavai 		break;
1309b509e89bSRishi Srivatsavai 	case MAC_PROP_WL_DESIRED_RATES:
1310b509e89bSRishi Srivatsavai 		break;
1311b509e89bSRishi Srivatsavai 	case MAC_PROP_PRIVATE:
1312*0dc2366fSVenugopal Iyer 		err = simnet_get_priv_prop(sdev, pr_name, wldp_length,
1313*0dc2366fSVenugopal Iyer 		    wldp_buf);
1314b509e89bSRishi Srivatsavai 		break;
1315b509e89bSRishi Srivatsavai 	default:
1316b509e89bSRishi Srivatsavai 		err = ENOTSUP;
1317b509e89bSRishi Srivatsavai 		break;
1318b509e89bSRishi Srivatsavai 	}
1319b509e89bSRishi Srivatsavai 
1320b509e89bSRishi Srivatsavai 	return (err);
1321b509e89bSRishi Srivatsavai }
1322*0dc2366fSVenugopal Iyer 
1323*0dc2366fSVenugopal Iyer static void
1324*0dc2366fSVenugopal Iyer simnet_priv_propinfo(const char *pr_name, mac_prop_info_handle_t prh)
1325*0dc2366fSVenugopal Iyer {
1326*0dc2366fSVenugopal Iyer 	char valstr[MAXNAMELEN];
1327*0dc2366fSVenugopal Iyer 
1328*0dc2366fSVenugopal Iyer 	bzero(valstr, sizeof (valstr));
1329*0dc2366fSVenugopal Iyer 
1330*0dc2366fSVenugopal Iyer 	if (strcmp(pr_name, "_wl_esslist") == 0) {
1331*0dc2366fSVenugopal Iyer 		(void) snprintf(valstr, sizeof (valstr), "%d", 0);
1332*0dc2366fSVenugopal Iyer 	}
1333*0dc2366fSVenugopal Iyer 
1334*0dc2366fSVenugopal Iyer 	if (strlen(valstr) > 0)
1335*0dc2366fSVenugopal Iyer 		mac_prop_info_set_default_str(prh, valstr);
1336*0dc2366fSVenugopal Iyer }
1337*0dc2366fSVenugopal Iyer 
1338*0dc2366fSVenugopal Iyer static void
1339*0dc2366fSVenugopal Iyer simnet_m_propinfo(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
1340*0dc2366fSVenugopal Iyer     mac_prop_info_handle_t prh)
1341*0dc2366fSVenugopal Iyer {
1342*0dc2366fSVenugopal Iyer 	simnet_dev_t *sdev = arg;
1343*0dc2366fSVenugopal Iyer 
1344*0dc2366fSVenugopal Iyer 	if (sdev->sd_type == DL_ETHER)
1345*0dc2366fSVenugopal Iyer 		return;
1346*0dc2366fSVenugopal Iyer 
1347*0dc2366fSVenugopal Iyer 	switch (wldp_pr_num) {
1348*0dc2366fSVenugopal Iyer 	case MAC_PROP_WL_BSSTYPE:
1349*0dc2366fSVenugopal Iyer 	case MAC_PROP_WL_ESS_LIST:
1350*0dc2366fSVenugopal Iyer 	case MAC_PROP_WL_SUPPORTED_RATES:
1351*0dc2366fSVenugopal Iyer 	case MAC_PROP_WL_RSSI:
1352*0dc2366fSVenugopal Iyer 		mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
1353*0dc2366fSVenugopal Iyer 		break;
1354*0dc2366fSVenugopal Iyer 	case MAC_PROP_PRIVATE:
1355*0dc2366fSVenugopal Iyer 		simnet_priv_propinfo(pr_name, prh);
1356*0dc2366fSVenugopal Iyer 		break;
1357*0dc2366fSVenugopal Iyer 	}
1358*0dc2366fSVenugopal Iyer }
1359