diff options
Diffstat (limited to 'drivers/net/wireless/libertas/wext.c')
-rw-r--r-- | drivers/net/wireless/libertas/wext.c | 363 |
1 files changed, 214 insertions, 149 deletions
diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index 8b3ed77860b3..82c3e5a50ea6 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c | |||
@@ -30,6 +30,14 @@ static inline void lbs_postpone_association_work(struct lbs_private *priv) | |||
30 | queue_delayed_work(priv->work_thread, &priv->assoc_work, HZ / 2); | 30 | queue_delayed_work(priv->work_thread, &priv->assoc_work, HZ / 2); |
31 | } | 31 | } |
32 | 32 | ||
33 | static inline void lbs_do_association_work(struct lbs_private *priv) | ||
34 | { | ||
35 | if (priv->surpriseremoved) | ||
36 | return; | ||
37 | cancel_delayed_work(&priv->assoc_work); | ||
38 | queue_delayed_work(priv->work_thread, &priv->assoc_work, 0); | ||
39 | } | ||
40 | |||
33 | static inline void lbs_cancel_association_work(struct lbs_private *priv) | 41 | static inline void lbs_cancel_association_work(struct lbs_private *priv) |
34 | { | 42 | { |
35 | cancel_delayed_work(&priv->assoc_work); | 43 | cancel_delayed_work(&priv->assoc_work); |
@@ -120,34 +128,6 @@ static struct chan_freq_power *find_cfp_by_band_and_freq( | |||
120 | return cfp; | 128 | return cfp; |
121 | } | 129 | } |
122 | 130 | ||
123 | |||
124 | /** | ||
125 | * @brief Set Radio On/OFF | ||
126 | * | ||
127 | * @param priv A pointer to struct lbs_private structure | ||
128 | * @option Radio Option | ||
129 | * @return 0 --success, otherwise fail | ||
130 | */ | ||
131 | static int lbs_radio_ioctl(struct lbs_private *priv, u8 option) | ||
132 | { | ||
133 | int ret = 0; | ||
134 | |||
135 | lbs_deb_enter(LBS_DEB_WEXT); | ||
136 | |||
137 | if (priv->radioon != option) { | ||
138 | lbs_deb_wext("switching radio %s\n", option ? "on" : "off"); | ||
139 | priv->radioon = option; | ||
140 | |||
141 | ret = lbs_prepare_and_send_command(priv, | ||
142 | CMD_802_11_RADIO_CONTROL, | ||
143 | CMD_ACT_SET, | ||
144 | CMD_OPTION_WAITFORRSP, 0, NULL); | ||
145 | } | ||
146 | |||
147 | lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); | ||
148 | return ret; | ||
149 | } | ||
150 | |||
151 | /** | 131 | /** |
152 | * @brief Copy active data rates based on adapter mode and status | 132 | * @brief Copy active data rates based on adapter mode and status |
153 | * | 133 | * |
@@ -294,21 +274,17 @@ static int lbs_set_rts(struct net_device *dev, struct iw_request_info *info, | |||
294 | { | 274 | { |
295 | int ret = 0; | 275 | int ret = 0; |
296 | struct lbs_private *priv = dev->priv; | 276 | struct lbs_private *priv = dev->priv; |
297 | u32 rthr = vwrq->value; | 277 | u32 val = vwrq->value; |
298 | 278 | ||
299 | lbs_deb_enter(LBS_DEB_WEXT); | 279 | lbs_deb_enter(LBS_DEB_WEXT); |
300 | 280 | ||
301 | if (vwrq->disabled) { | 281 | if (vwrq->disabled) |
302 | priv->rtsthsd = rthr = MRVDRV_RTS_MAX_VALUE; | 282 | val = MRVDRV_RTS_MAX_VALUE; |
303 | } else { | 283 | |
304 | if (rthr < MRVDRV_RTS_MIN_VALUE || rthr > MRVDRV_RTS_MAX_VALUE) | 284 | if (val > MRVDRV_RTS_MAX_VALUE) /* min rts value is 0 */ |
305 | return -EINVAL; | 285 | return -EINVAL; |
306 | priv->rtsthsd = rthr; | ||
307 | } | ||
308 | 286 | ||
309 | ret = lbs_prepare_and_send_command(priv, CMD_802_11_SNMP_MIB, | 287 | ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_RTS_THRESHOLD, (u16) val); |
310 | CMD_ACT_SET, CMD_OPTION_WAITFORRSP, | ||
311 | OID_802_11_RTS_THRESHOLD, &rthr); | ||
312 | 288 | ||
313 | lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); | 289 | lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); |
314 | return ret; | 290 | return ret; |
@@ -317,21 +293,18 @@ static int lbs_set_rts(struct net_device *dev, struct iw_request_info *info, | |||
317 | static int lbs_get_rts(struct net_device *dev, struct iw_request_info *info, | 293 | static int lbs_get_rts(struct net_device *dev, struct iw_request_info *info, |
318 | struct iw_param *vwrq, char *extra) | 294 | struct iw_param *vwrq, char *extra) |
319 | { | 295 | { |
320 | int ret = 0; | ||
321 | struct lbs_private *priv = dev->priv; | 296 | struct lbs_private *priv = dev->priv; |
297 | int ret = 0; | ||
298 | u16 val = 0; | ||
322 | 299 | ||
323 | lbs_deb_enter(LBS_DEB_WEXT); | 300 | lbs_deb_enter(LBS_DEB_WEXT); |
324 | 301 | ||
325 | priv->rtsthsd = 0; | 302 | ret = lbs_get_snmp_mib(priv, SNMP_MIB_OID_RTS_THRESHOLD, &val); |
326 | ret = lbs_prepare_and_send_command(priv, CMD_802_11_SNMP_MIB, | ||
327 | CMD_ACT_GET, CMD_OPTION_WAITFORRSP, | ||
328 | OID_802_11_RTS_THRESHOLD, NULL); | ||
329 | if (ret) | 303 | if (ret) |
330 | goto out; | 304 | goto out; |
331 | 305 | ||
332 | vwrq->value = priv->rtsthsd; | 306 | vwrq->value = val; |
333 | vwrq->disabled = ((vwrq->value < MRVDRV_RTS_MIN_VALUE) | 307 | vwrq->disabled = val > MRVDRV_RTS_MAX_VALUE; /* min rts value is 0 */ |
334 | || (vwrq->value > MRVDRV_RTS_MAX_VALUE)); | ||
335 | vwrq->fixed = 1; | 308 | vwrq->fixed = 1; |
336 | 309 | ||
337 | out: | 310 | out: |
@@ -342,24 +315,19 @@ out: | |||
342 | static int lbs_set_frag(struct net_device *dev, struct iw_request_info *info, | 315 | static int lbs_set_frag(struct net_device *dev, struct iw_request_info *info, |
343 | struct iw_param *vwrq, char *extra) | 316 | struct iw_param *vwrq, char *extra) |
344 | { | 317 | { |
345 | int ret = 0; | ||
346 | u32 fthr = vwrq->value; | ||
347 | struct lbs_private *priv = dev->priv; | 318 | struct lbs_private *priv = dev->priv; |
319 | int ret = 0; | ||
320 | u32 val = vwrq->value; | ||
348 | 321 | ||
349 | lbs_deb_enter(LBS_DEB_WEXT); | 322 | lbs_deb_enter(LBS_DEB_WEXT); |
350 | 323 | ||
351 | if (vwrq->disabled) { | 324 | if (vwrq->disabled) |
352 | priv->fragthsd = fthr = MRVDRV_FRAG_MAX_VALUE; | 325 | val = MRVDRV_FRAG_MAX_VALUE; |
353 | } else { | 326 | |
354 | if (fthr < MRVDRV_FRAG_MIN_VALUE | 327 | if (val < MRVDRV_FRAG_MIN_VALUE || val > MRVDRV_FRAG_MAX_VALUE) |
355 | || fthr > MRVDRV_FRAG_MAX_VALUE) | 328 | return -EINVAL; |
356 | return -EINVAL; | ||
357 | priv->fragthsd = fthr; | ||
358 | } | ||
359 | 329 | ||
360 | ret = lbs_prepare_and_send_command(priv, CMD_802_11_SNMP_MIB, | 330 | ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_FRAG_THRESHOLD, (u16) val); |
361 | CMD_ACT_SET, CMD_OPTION_WAITFORRSP, | ||
362 | OID_802_11_FRAGMENTATION_THRESHOLD, &fthr); | ||
363 | 331 | ||
364 | lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); | 332 | lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); |
365 | return ret; | 333 | return ret; |
@@ -368,22 +336,19 @@ static int lbs_set_frag(struct net_device *dev, struct iw_request_info *info, | |||
368 | static int lbs_get_frag(struct net_device *dev, struct iw_request_info *info, | 336 | static int lbs_get_frag(struct net_device *dev, struct iw_request_info *info, |
369 | struct iw_param *vwrq, char *extra) | 337 | struct iw_param *vwrq, char *extra) |
370 | { | 338 | { |
371 | int ret = 0; | ||
372 | struct lbs_private *priv = dev->priv; | 339 | struct lbs_private *priv = dev->priv; |
340 | int ret = 0; | ||
341 | u16 val = 0; | ||
373 | 342 | ||
374 | lbs_deb_enter(LBS_DEB_WEXT); | 343 | lbs_deb_enter(LBS_DEB_WEXT); |
375 | 344 | ||
376 | priv->fragthsd = 0; | 345 | ret = lbs_get_snmp_mib(priv, SNMP_MIB_OID_FRAG_THRESHOLD, &val); |
377 | ret = lbs_prepare_and_send_command(priv, | ||
378 | CMD_802_11_SNMP_MIB, | ||
379 | CMD_ACT_GET, CMD_OPTION_WAITFORRSP, | ||
380 | OID_802_11_FRAGMENTATION_THRESHOLD, NULL); | ||
381 | if (ret) | 346 | if (ret) |
382 | goto out; | 347 | goto out; |
383 | 348 | ||
384 | vwrq->value = priv->fragthsd; | 349 | vwrq->value = val; |
385 | vwrq->disabled = ((vwrq->value < MRVDRV_FRAG_MIN_VALUE) | 350 | vwrq->disabled = ((val < MRVDRV_FRAG_MIN_VALUE) |
386 | || (vwrq->value > MRVDRV_FRAG_MAX_VALUE)); | 351 | || (val > MRVDRV_FRAG_MAX_VALUE)); |
387 | vwrq->fixed = 1; | 352 | vwrq->fixed = 1; |
388 | 353 | ||
389 | out: | 354 | out: |
@@ -410,7 +375,7 @@ static int mesh_wlan_get_mode(struct net_device *dev, | |||
410 | { | 375 | { |
411 | lbs_deb_enter(LBS_DEB_WEXT); | 376 | lbs_deb_enter(LBS_DEB_WEXT); |
412 | 377 | ||
413 | *uwrq = IW_MODE_REPEAT ; | 378 | *uwrq = IW_MODE_REPEAT; |
414 | 379 | ||
415 | lbs_deb_leave(LBS_DEB_WEXT); | 380 | lbs_deb_leave(LBS_DEB_WEXT); |
416 | return 0; | 381 | return 0; |
@@ -420,28 +385,30 @@ static int lbs_get_txpow(struct net_device *dev, | |||
420 | struct iw_request_info *info, | 385 | struct iw_request_info *info, |
421 | struct iw_param *vwrq, char *extra) | 386 | struct iw_param *vwrq, char *extra) |
422 | { | 387 | { |
423 | int ret = 0; | ||
424 | struct lbs_private *priv = dev->priv; | 388 | struct lbs_private *priv = dev->priv; |
389 | s16 curlevel = 0; | ||
390 | int ret = 0; | ||
425 | 391 | ||
426 | lbs_deb_enter(LBS_DEB_WEXT); | 392 | lbs_deb_enter(LBS_DEB_WEXT); |
427 | 393 | ||
428 | ret = lbs_prepare_and_send_command(priv, | 394 | if (!priv->radio_on) { |
429 | CMD_802_11_RF_TX_POWER, | 395 | lbs_deb_wext("tx power off\n"); |
430 | CMD_ACT_TX_POWER_OPT_GET, | 396 | vwrq->value = 0; |
431 | CMD_OPTION_WAITFORRSP, 0, NULL); | 397 | vwrq->disabled = 1; |
398 | goto out; | ||
399 | } | ||
432 | 400 | ||
401 | ret = lbs_get_tx_power(priv, &curlevel, NULL, NULL); | ||
433 | if (ret) | 402 | if (ret) |
434 | goto out; | 403 | goto out; |
435 | 404 | ||
436 | lbs_deb_wext("tx power level %d dbm\n", priv->txpowerlevel); | 405 | lbs_deb_wext("tx power level %d dbm\n", curlevel); |
437 | vwrq->value = priv->txpowerlevel; | 406 | priv->txpower_cur = curlevel; |
407 | |||
408 | vwrq->value = curlevel; | ||
438 | vwrq->fixed = 1; | 409 | vwrq->fixed = 1; |
439 | if (priv->radioon) { | 410 | vwrq->disabled = 0; |
440 | vwrq->disabled = 0; | 411 | vwrq->flags = IW_TXPOW_DBM; |
441 | vwrq->flags = IW_TXPOW_DBM; | ||
442 | } else { | ||
443 | vwrq->disabled = 1; | ||
444 | } | ||
445 | 412 | ||
446 | out: | 413 | out: |
447 | lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); | 414 | lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); |
@@ -451,31 +418,44 @@ out: | |||
451 | static int lbs_set_retry(struct net_device *dev, struct iw_request_info *info, | 418 | static int lbs_set_retry(struct net_device *dev, struct iw_request_info *info, |
452 | struct iw_param *vwrq, char *extra) | 419 | struct iw_param *vwrq, char *extra) |
453 | { | 420 | { |
454 | int ret = 0; | ||
455 | struct lbs_private *priv = dev->priv; | 421 | struct lbs_private *priv = dev->priv; |
422 | int ret = 0; | ||
423 | u16 slimit = 0, llimit = 0; | ||
456 | 424 | ||
457 | lbs_deb_enter(LBS_DEB_WEXT); | 425 | lbs_deb_enter(LBS_DEB_WEXT); |
458 | 426 | ||
459 | if (vwrq->flags == IW_RETRY_LIMIT) { | 427 | if ((vwrq->flags & IW_RETRY_TYPE) != IW_RETRY_LIMIT) |
460 | /* The MAC has a 4-bit Total_Tx_Count register | 428 | return -EOPNOTSUPP; |
461 | Total_Tx_Count = 1 + Tx_Retry_Count */ | 429 | |
430 | /* The MAC has a 4-bit Total_Tx_Count register | ||
431 | Total_Tx_Count = 1 + Tx_Retry_Count */ | ||
462 | #define TX_RETRY_MIN 0 | 432 | #define TX_RETRY_MIN 0 |
463 | #define TX_RETRY_MAX 14 | 433 | #define TX_RETRY_MAX 14 |
464 | if (vwrq->value < TX_RETRY_MIN || vwrq->value > TX_RETRY_MAX) | 434 | if (vwrq->value < TX_RETRY_MIN || vwrq->value > TX_RETRY_MAX) |
465 | return -EINVAL; | 435 | return -EINVAL; |
466 | 436 | ||
467 | /* Adding 1 to convert retry count to try count */ | 437 | /* Add 1 to convert retry count to try count */ |
468 | priv->txretrycount = vwrq->value + 1; | 438 | if (vwrq->flags & IW_RETRY_SHORT) |
439 | slimit = (u16) (vwrq->value + 1); | ||
440 | else if (vwrq->flags & IW_RETRY_LONG) | ||
441 | llimit = (u16) (vwrq->value + 1); | ||
442 | else | ||
443 | slimit = llimit = (u16) (vwrq->value + 1); /* set both */ | ||
469 | 444 | ||
470 | ret = lbs_prepare_and_send_command(priv, CMD_802_11_SNMP_MIB, | 445 | if (llimit) { |
471 | CMD_ACT_SET, | 446 | ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_LONG_RETRY_LIMIT, |
472 | CMD_OPTION_WAITFORRSP, | 447 | llimit); |
473 | OID_802_11_TX_RETRYCOUNT, NULL); | 448 | if (ret) |
449 | goto out; | ||
450 | } | ||
474 | 451 | ||
452 | if (slimit) { | ||
453 | /* txretrycount follows the short retry limit */ | ||
454 | priv->txretrycount = slimit; | ||
455 | ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_SHORT_RETRY_LIMIT, | ||
456 | slimit); | ||
475 | if (ret) | 457 | if (ret) |
476 | goto out; | 458 | goto out; |
477 | } else { | ||
478 | return -EOPNOTSUPP; | ||
479 | } | 459 | } |
480 | 460 | ||
481 | out: | 461 | out: |
@@ -488,22 +468,30 @@ static int lbs_get_retry(struct net_device *dev, struct iw_request_info *info, | |||
488 | { | 468 | { |
489 | struct lbs_private *priv = dev->priv; | 469 | struct lbs_private *priv = dev->priv; |
490 | int ret = 0; | 470 | int ret = 0; |
471 | u16 val = 0; | ||
491 | 472 | ||
492 | lbs_deb_enter(LBS_DEB_WEXT); | 473 | lbs_deb_enter(LBS_DEB_WEXT); |
493 | 474 | ||
494 | priv->txretrycount = 0; | ||
495 | ret = lbs_prepare_and_send_command(priv, | ||
496 | CMD_802_11_SNMP_MIB, | ||
497 | CMD_ACT_GET, CMD_OPTION_WAITFORRSP, | ||
498 | OID_802_11_TX_RETRYCOUNT, NULL); | ||
499 | if (ret) | ||
500 | goto out; | ||
501 | |||
502 | vwrq->disabled = 0; | 475 | vwrq->disabled = 0; |
503 | if (!vwrq->flags) { | 476 | |
504 | vwrq->flags = IW_RETRY_LIMIT; | 477 | if (vwrq->flags & IW_RETRY_LONG) { |
478 | ret = lbs_get_snmp_mib(priv, SNMP_MIB_OID_LONG_RETRY_LIMIT, &val); | ||
479 | if (ret) | ||
480 | goto out; | ||
481 | |||
482 | /* Subtract 1 to convert try count to retry count */ | ||
483 | vwrq->value = val - 1; | ||
484 | vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG; | ||
485 | } else { | ||
486 | ret = lbs_get_snmp_mib(priv, SNMP_MIB_OID_SHORT_RETRY_LIMIT, &val); | ||
487 | if (ret) | ||
488 | goto out; | ||
489 | |||
490 | /* txretry count follows the short retry limit */ | ||
491 | priv->txretrycount = val; | ||
505 | /* Subtract 1 to convert try count to retry count */ | 492 | /* Subtract 1 to convert try count to retry count */ |
506 | vwrq->value = priv->txretrycount - 1; | 493 | vwrq->value = val - 1; |
494 | vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_SHORT; | ||
507 | } | 495 | } |
508 | 496 | ||
509 | out: | 497 | out: |
@@ -693,22 +681,12 @@ static int lbs_get_range(struct net_device *dev, struct iw_request_info *info, | |||
693 | 681 | ||
694 | range->sensitivity = 0; | 682 | range->sensitivity = 0; |
695 | 683 | ||
696 | /* | 684 | /* Setup the supported power level ranges */ |
697 | * Setup the supported power level ranges | ||
698 | */ | ||
699 | memset(range->txpower, 0, sizeof(range->txpower)); | 685 | memset(range->txpower, 0, sizeof(range->txpower)); |
700 | range->txpower[0] = 5; | 686 | range->txpower_capa = IW_TXPOW_DBM | IW_TXPOW_RANGE; |
701 | range->txpower[1] = 7; | 687 | range->txpower[0] = priv->txpower_min; |
702 | range->txpower[2] = 9; | 688 | range->txpower[1] = priv->txpower_max; |
703 | range->txpower[3] = 11; | 689 | range->num_txpower = 2; |
704 | range->txpower[4] = 13; | ||
705 | range->txpower[5] = 15; | ||
706 | range->txpower[6] = 17; | ||
707 | range->txpower[7] = 19; | ||
708 | |||
709 | range->num_txpower = 8; | ||
710 | range->txpower_capa = IW_TXPOW_DBM; | ||
711 | range->txpower_capa |= IW_TXPOW_RANGE; | ||
712 | 690 | ||
713 | range->event_capa[0] = (IW_EVENT_CAPA_K_0 | | 691 | range->event_capa[0] = (IW_EVENT_CAPA_K_0 | |
714 | IW_EVENT_CAPA_MASK(SIOCGIWAP) | | 692 | IW_EVENT_CAPA_MASK(SIOCGIWAP) | |
@@ -998,9 +976,11 @@ static int lbs_mesh_set_freq(struct net_device *dev, | |||
998 | if (fwrq->m != priv->curbssparams.channel) { | 976 | if (fwrq->m != priv->curbssparams.channel) { |
999 | lbs_deb_wext("mesh channel change forces eth disconnect\n"); | 977 | lbs_deb_wext("mesh channel change forces eth disconnect\n"); |
1000 | if (priv->mode == IW_MODE_INFRA) | 978 | if (priv->mode == IW_MODE_INFRA) |
1001 | lbs_send_deauthentication(priv); | 979 | lbs_cmd_80211_deauthenticate(priv, |
980 | priv->curbssparams.bssid, | ||
981 | WLAN_REASON_DEAUTH_LEAVING); | ||
1002 | else if (priv->mode == IW_MODE_ADHOC) | 982 | else if (priv->mode == IW_MODE_ADHOC) |
1003 | lbs_stop_adhoc_network(priv); | 983 | lbs_adhoc_stop(priv); |
1004 | } | 984 | } |
1005 | lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, fwrq->m); | 985 | lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, fwrq->m); |
1006 | lbs_update_channel(priv); | 986 | lbs_update_channel(priv); |
@@ -1045,6 +1025,18 @@ static int lbs_set_rate(struct net_device *dev, struct iw_request_info *info, | |||
1045 | new_rate); | 1025 | new_rate); |
1046 | goto out; | 1026 | goto out; |
1047 | } | 1027 | } |
1028 | if (priv->fwrelease < 0x09000000) { | ||
1029 | ret = lbs_set_power_adapt_cfg(priv, 0, | ||
1030 | POW_ADAPT_DEFAULT_P0, | ||
1031 | POW_ADAPT_DEFAULT_P1, | ||
1032 | POW_ADAPT_DEFAULT_P2); | ||
1033 | if (ret) | ||
1034 | goto out; | ||
1035 | } | ||
1036 | ret = lbs_set_tpc_cfg(priv, 0, TPC_DEFAULT_P0, TPC_DEFAULT_P1, | ||
1037 | TPC_DEFAULT_P2, 1); | ||
1038 | if (ret) | ||
1039 | goto out; | ||
1048 | } | 1040 | } |
1049 | 1041 | ||
1050 | /* Try the newer command first (Firmware Spec 5.1 and above) */ | 1042 | /* Try the newer command first (Firmware Spec 5.1 and above) */ |
@@ -1612,12 +1604,26 @@ static int lbs_set_encodeext(struct net_device *dev, | |||
1612 | set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags); | 1604 | set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags); |
1613 | } | 1605 | } |
1614 | 1606 | ||
1615 | disable_wep (assoc_req); | 1607 | /* Only disable wep if necessary: can't waste time here. */ |
1608 | if (priv->mac_control & CMD_ACT_MAC_WEP_ENABLE) | ||
1609 | disable_wep(assoc_req); | ||
1616 | } | 1610 | } |
1617 | 1611 | ||
1618 | out: | 1612 | out: |
1619 | if (ret == 0) { | 1613 | if (ret == 0) { |
1620 | lbs_postpone_association_work(priv); | 1614 | /* 802.1x and WPA rekeying must happen as quickly as possible, |
1615 | * especially during the 4-way handshake; thus if in | ||
1616 | * infrastructure mode, and either (a) 802.1x is enabled or | ||
1617 | * (b) WPA is being used, set the key right away. | ||
1618 | */ | ||
1619 | if (assoc_req->mode == IW_MODE_INFRA && | ||
1620 | ((assoc_req->secinfo.key_mgmt & IW_AUTH_KEY_MGMT_802_1X) || | ||
1621 | (assoc_req->secinfo.key_mgmt & IW_AUTH_KEY_MGMT_PSK) || | ||
1622 | assoc_req->secinfo.WPAenabled || | ||
1623 | assoc_req->secinfo.WPA2enabled)) { | ||
1624 | lbs_do_association_work(priv); | ||
1625 | } else | ||
1626 | lbs_postpone_association_work(priv); | ||
1621 | } else { | 1627 | } else { |
1622 | lbs_cancel_association_work(priv); | 1628 | lbs_cancel_association_work(priv); |
1623 | } | 1629 | } |
@@ -1725,13 +1731,17 @@ static int lbs_set_auth(struct net_device *dev, | |||
1725 | case IW_AUTH_TKIP_COUNTERMEASURES: | 1731 | case IW_AUTH_TKIP_COUNTERMEASURES: |
1726 | case IW_AUTH_CIPHER_PAIRWISE: | 1732 | case IW_AUTH_CIPHER_PAIRWISE: |
1727 | case IW_AUTH_CIPHER_GROUP: | 1733 | case IW_AUTH_CIPHER_GROUP: |
1728 | case IW_AUTH_KEY_MGMT: | ||
1729 | case IW_AUTH_DROP_UNENCRYPTED: | 1734 | case IW_AUTH_DROP_UNENCRYPTED: |
1730 | /* | 1735 | /* |
1731 | * libertas does not use these parameters | 1736 | * libertas does not use these parameters |
1732 | */ | 1737 | */ |
1733 | break; | 1738 | break; |
1734 | 1739 | ||
1740 | case IW_AUTH_KEY_MGMT: | ||
1741 | assoc_req->secinfo.key_mgmt = dwrq->value; | ||
1742 | updated = 1; | ||
1743 | break; | ||
1744 | |||
1735 | case IW_AUTH_WPA_VERSION: | 1745 | case IW_AUTH_WPA_VERSION: |
1736 | if (dwrq->value & IW_AUTH_WPA_VERSION_DISABLED) { | 1746 | if (dwrq->value & IW_AUTH_WPA_VERSION_DISABLED) { |
1737 | assoc_req->secinfo.WPAenabled = 0; | 1747 | assoc_req->secinfo.WPAenabled = 0; |
@@ -1811,6 +1821,10 @@ static int lbs_get_auth(struct net_device *dev, | |||
1811 | lbs_deb_enter(LBS_DEB_WEXT); | 1821 | lbs_deb_enter(LBS_DEB_WEXT); |
1812 | 1822 | ||
1813 | switch (dwrq->flags & IW_AUTH_INDEX) { | 1823 | switch (dwrq->flags & IW_AUTH_INDEX) { |
1824 | case IW_AUTH_KEY_MGMT: | ||
1825 | dwrq->value = priv->secinfo.key_mgmt; | ||
1826 | break; | ||
1827 | |||
1814 | case IW_AUTH_WPA_VERSION: | 1828 | case IW_AUTH_WPA_VERSION: |
1815 | dwrq->value = 0; | 1829 | dwrq->value = 0; |
1816 | if (priv->secinfo.WPAenabled) | 1830 | if (priv->secinfo.WPAenabled) |
@@ -1844,39 +1858,77 @@ static int lbs_set_txpow(struct net_device *dev, struct iw_request_info *info, | |||
1844 | { | 1858 | { |
1845 | int ret = 0; | 1859 | int ret = 0; |
1846 | struct lbs_private *priv = dev->priv; | 1860 | struct lbs_private *priv = dev->priv; |
1847 | 1861 | s16 dbm = (s16) vwrq->value; | |
1848 | u16 dbm; | ||
1849 | 1862 | ||
1850 | lbs_deb_enter(LBS_DEB_WEXT); | 1863 | lbs_deb_enter(LBS_DEB_WEXT); |
1851 | 1864 | ||
1852 | if (vwrq->disabled) { | 1865 | if (vwrq->disabled) { |
1853 | lbs_radio_ioctl(priv, RADIO_OFF); | 1866 | lbs_set_radio(priv, RADIO_PREAMBLE_AUTO, 0); |
1854 | return 0; | 1867 | goto out; |
1855 | } | 1868 | } |
1856 | 1869 | ||
1857 | priv->preamble = CMD_TYPE_AUTO_PREAMBLE; | 1870 | if (vwrq->fixed == 0) { |
1858 | 1871 | /* User requests automatic tx power control, however there are | |
1859 | lbs_radio_ioctl(priv, RADIO_ON); | 1872 | * many auto tx settings. For now use firmware defaults until |
1873 | * we come up with a good way to expose these to the user. */ | ||
1874 | if (priv->fwrelease < 0x09000000) { | ||
1875 | ret = lbs_set_power_adapt_cfg(priv, 1, | ||
1876 | POW_ADAPT_DEFAULT_P0, | ||
1877 | POW_ADAPT_DEFAULT_P1, | ||
1878 | POW_ADAPT_DEFAULT_P2); | ||
1879 | if (ret) | ||
1880 | goto out; | ||
1881 | } | ||
1882 | ret = lbs_set_tpc_cfg(priv, 0, TPC_DEFAULT_P0, TPC_DEFAULT_P1, | ||
1883 | TPC_DEFAULT_P2, 1); | ||
1884 | if (ret) | ||
1885 | goto out; | ||
1886 | dbm = priv->txpower_max; | ||
1887 | } else { | ||
1888 | /* Userspace check in iwrange if it should use dBm or mW, | ||
1889 | * therefore this should never happen... Jean II */ | ||
1890 | if ((vwrq->flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) { | ||
1891 | ret = -EOPNOTSUPP; | ||
1892 | goto out; | ||
1893 | } | ||
1860 | 1894 | ||
1861 | /* Userspace check in iwrange if it should use dBm or mW, | 1895 | /* Validate requested power level against firmware allowed |
1862 | * therefore this should never happen... Jean II */ | 1896 | * levels */ |
1863 | if ((vwrq->flags & IW_TXPOW_TYPE) == IW_TXPOW_MWATT) { | 1897 | if (priv->txpower_min && (dbm < priv->txpower_min)) { |
1864 | return -EOPNOTSUPP; | 1898 | ret = -EINVAL; |
1865 | } else | 1899 | goto out; |
1866 | dbm = (u16) vwrq->value; | 1900 | } |
1867 | 1901 | ||
1868 | /* auto tx power control */ | 1902 | if (priv->txpower_max && (dbm > priv->txpower_max)) { |
1903 | ret = -EINVAL; | ||
1904 | goto out; | ||
1905 | } | ||
1906 | if (priv->fwrelease < 0x09000000) { | ||
1907 | ret = lbs_set_power_adapt_cfg(priv, 0, | ||
1908 | POW_ADAPT_DEFAULT_P0, | ||
1909 | POW_ADAPT_DEFAULT_P1, | ||
1910 | POW_ADAPT_DEFAULT_P2); | ||
1911 | if (ret) | ||
1912 | goto out; | ||
1913 | } | ||
1914 | ret = lbs_set_tpc_cfg(priv, 0, TPC_DEFAULT_P0, TPC_DEFAULT_P1, | ||
1915 | TPC_DEFAULT_P2, 1); | ||
1916 | if (ret) | ||
1917 | goto out; | ||
1918 | } | ||
1869 | 1919 | ||
1870 | if (vwrq->fixed == 0) | 1920 | /* If the radio was off, turn it on */ |
1871 | dbm = 0xffff; | 1921 | if (!priv->radio_on) { |
1922 | ret = lbs_set_radio(priv, RADIO_PREAMBLE_AUTO, 1); | ||
1923 | if (ret) | ||
1924 | goto out; | ||
1925 | } | ||
1872 | 1926 | ||
1873 | lbs_deb_wext("txpower set %d dbm\n", dbm); | 1927 | lbs_deb_wext("txpower set %d dBm\n", dbm); |
1874 | 1928 | ||
1875 | ret = lbs_prepare_and_send_command(priv, | 1929 | ret = lbs_set_tx_power(priv, dbm); |
1876 | CMD_802_11_RF_TX_POWER, | ||
1877 | CMD_ACT_TX_POWER_OPT_SET_LOW, | ||
1878 | CMD_OPTION_WAITFORRSP, 0, (void *)&dbm); | ||
1879 | 1930 | ||
1931 | out: | ||
1880 | lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); | 1932 | lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); |
1881 | return ret; | 1933 | return ret; |
1882 | } | 1934 | } |
@@ -1928,6 +1980,11 @@ static int lbs_set_essid(struct net_device *dev, struct iw_request_info *info, | |||
1928 | 1980 | ||
1929 | lbs_deb_enter(LBS_DEB_WEXT); | 1981 | lbs_deb_enter(LBS_DEB_WEXT); |
1930 | 1982 | ||
1983 | if (!priv->radio_on) { | ||
1984 | ret = -EINVAL; | ||
1985 | goto out; | ||
1986 | } | ||
1987 | |||
1931 | /* Check the size of the string */ | 1988 | /* Check the size of the string */ |
1932 | if (in_ssid_len > IW_ESSID_MAX_SIZE) { | 1989 | if (in_ssid_len > IW_ESSID_MAX_SIZE) { |
1933 | ret = -E2BIG; | 1990 | ret = -E2BIG; |
@@ -2005,6 +2062,11 @@ static int lbs_mesh_set_essid(struct net_device *dev, | |||
2005 | 2062 | ||
2006 | lbs_deb_enter(LBS_DEB_WEXT); | 2063 | lbs_deb_enter(LBS_DEB_WEXT); |
2007 | 2064 | ||
2065 | if (!priv->radio_on) { | ||
2066 | ret = -EINVAL; | ||
2067 | goto out; | ||
2068 | } | ||
2069 | |||
2008 | /* Check the size of the string */ | 2070 | /* Check the size of the string */ |
2009 | if (dwrq->length > IW_ESSID_MAX_SIZE) { | 2071 | if (dwrq->length > IW_ESSID_MAX_SIZE) { |
2010 | ret = -E2BIG; | 2072 | ret = -E2BIG; |
@@ -2046,6 +2108,9 @@ static int lbs_set_wap(struct net_device *dev, struct iw_request_info *info, | |||
2046 | 2108 | ||
2047 | lbs_deb_enter(LBS_DEB_WEXT); | 2109 | lbs_deb_enter(LBS_DEB_WEXT); |
2048 | 2110 | ||
2111 | if (!priv->radio_on) | ||
2112 | return -EINVAL; | ||
2113 | |||
2049 | if (awrq->sa_family != ARPHRD_ETHER) | 2114 | if (awrq->sa_family != ARPHRD_ETHER) |
2050 | return -EINVAL; | 2115 | return -EINVAL; |
2051 | 2116 | ||