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