Commit d5db2dfa authored by Dan Williams's avatar Dan Williams Committed by John W. Linville

libertas: convert CMD_802_11_RADIO_CONTROL to a direct command

and return errors for operations like join & scan that aren't possible
when the radio is turned off.
Signed-off-by: default avatarDan Williams <dcbw@redhat.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 191bb40e
...@@ -25,7 +25,7 @@ static const u8 bssid_off[ETH_ALEN] __attribute__ ((aligned (2))) = ...@@ -25,7 +25,7 @@ static const u8 bssid_off[ETH_ALEN] __attribute__ ((aligned (2))) =
* @brief Associate to a specific BSS discovered in a scan * @brief Associate to a specific BSS discovered in a scan
* *
* @param priv A pointer to struct lbs_private structure * @param priv A pointer to struct lbs_private structure
* @param pbssdesc Pointer to the BSS descriptor to associate with. * @param assoc_req The association request describing the BSS to associate with
* *
* @return 0-success, otherwise fail * @return 0-success, otherwise fail
*/ */
...@@ -33,29 +33,29 @@ static int lbs_associate(struct lbs_private *priv, ...@@ -33,29 +33,29 @@ static int lbs_associate(struct lbs_private *priv,
struct assoc_request *assoc_req) struct assoc_request *assoc_req)
{ {
int ret; int ret;
u8 preamble = RADIO_PREAMBLE_LONG;
lbs_deb_enter(LBS_DEB_ASSOC); lbs_deb_enter(LBS_DEB_ASSOC);
ret = lbs_prepare_and_send_command(priv, CMD_802_11_AUTHENTICATE, ret = lbs_prepare_and_send_command(priv, CMD_802_11_AUTHENTICATE,
0, CMD_OPTION_WAITFORRSP, 0, CMD_OPTION_WAITFORRSP,
0, assoc_req->bss.bssid); 0, assoc_req->bss.bssid);
if (ret) if (ret)
goto done; goto out;
/* set preamble to firmware */ /* Use short preamble only when both the BSS and firmware support it */
if ((priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) && if ((priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) &&
(assoc_req->bss.capability & WLAN_CAPABILITY_SHORT_PREAMBLE)) (assoc_req->bss.capability & WLAN_CAPABILITY_SHORT_PREAMBLE))
priv->preamble = CMD_TYPE_SHORT_PREAMBLE; preamble = RADIO_PREAMBLE_SHORT;
else
priv->preamble = CMD_TYPE_LONG_PREAMBLE;
lbs_set_radio_control(priv); ret = lbs_set_radio(priv, preamble, 1);
if (ret)
goto out;
ret = lbs_prepare_and_send_command(priv, CMD_802_11_ASSOCIATE, ret = lbs_prepare_and_send_command(priv, CMD_802_11_ASSOCIATE,
0, CMD_OPTION_WAITFORRSP, 0, assoc_req); 0, CMD_OPTION_WAITFORRSP, 0, assoc_req);
done: out:
lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
return ret; return ret;
} }
...@@ -64,8 +64,7 @@ static int lbs_associate(struct lbs_private *priv, ...@@ -64,8 +64,7 @@ static int lbs_associate(struct lbs_private *priv,
* @brief Join an adhoc network found in a previous scan * @brief Join an adhoc network found in a previous scan
* *
* @param priv A pointer to struct lbs_private structure * @param priv A pointer to struct lbs_private structure
* @param pbssdesc Pointer to a BSS descriptor found in a previous scan * @param assoc_req The association request describing the BSS to join
* to attempt to join
* *
* @return 0--success, -1--fail * @return 0--success, -1--fail
*/ */
...@@ -74,6 +73,9 @@ static int lbs_join_adhoc_network(struct lbs_private *priv, ...@@ -74,6 +73,9 @@ static int lbs_join_adhoc_network(struct lbs_private *priv,
{ {
struct bss_descriptor *bss = &assoc_req->bss; struct bss_descriptor *bss = &assoc_req->bss;
int ret = 0; int ret = 0;
u8 preamble = RADIO_PREAMBLE_LONG;
lbs_deb_enter(LBS_DEB_ASSOC);
lbs_deb_join("current SSID '%s', ssid length %u\n", lbs_deb_join("current SSID '%s', ssid length %u\n",
escape_essid(priv->curbssparams.ssid, escape_essid(priv->curbssparams.ssid,
...@@ -106,18 +108,16 @@ static int lbs_join_adhoc_network(struct lbs_private *priv, ...@@ -106,18 +108,16 @@ static int lbs_join_adhoc_network(struct lbs_private *priv,
goto out; goto out;
} }
/* Use shortpreamble only when both creator and card supports /* Use short preamble only when both the BSS and firmware support it */
short preamble */ if ((priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) &&
if (!(bss->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) || (bss->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)) {
!(priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)) {
lbs_deb_join("AdhocJoin: Long preamble\n");
priv->preamble = CMD_TYPE_LONG_PREAMBLE;
} else {
lbs_deb_join("AdhocJoin: Short preamble\n"); lbs_deb_join("AdhocJoin: Short preamble\n");
priv->preamble = CMD_TYPE_SHORT_PREAMBLE; preamble = RADIO_PREAMBLE_SHORT;
} }
lbs_set_radio_control(priv); ret = lbs_set_radio(priv, preamble, 1);
if (ret)
goto out;
lbs_deb_join("AdhocJoin: channel = %d\n", assoc_req->channel); lbs_deb_join("AdhocJoin: channel = %d\n", assoc_req->channel);
lbs_deb_join("AdhocJoin: band = %c\n", assoc_req->band); lbs_deb_join("AdhocJoin: band = %c\n", assoc_req->band);
...@@ -129,6 +129,7 @@ static int lbs_join_adhoc_network(struct lbs_private *priv, ...@@ -129,6 +129,7 @@ static int lbs_join_adhoc_network(struct lbs_private *priv,
OID_802_11_SSID, assoc_req); OID_802_11_SSID, assoc_req);
out: out:
lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
return ret; return ret;
} }
...@@ -136,25 +137,27 @@ static int lbs_join_adhoc_network(struct lbs_private *priv, ...@@ -136,25 +137,27 @@ static int lbs_join_adhoc_network(struct lbs_private *priv,
* @brief Start an Adhoc Network * @brief Start an Adhoc Network
* *
* @param priv A pointer to struct lbs_private structure * @param priv A pointer to struct lbs_private structure
* @param adhocssid The ssid of the Adhoc Network * @param assoc_req The association request describing the BSS to start
* @return 0--success, -1--fail * @return 0--success, -1--fail
*/ */
static int lbs_start_adhoc_network(struct lbs_private *priv, static int lbs_start_adhoc_network(struct lbs_private *priv,
struct assoc_request *assoc_req) struct assoc_request *assoc_req)
{ {
int ret = 0; int ret = 0;
u8 preamble = RADIO_PREAMBLE_LONG;
lbs_deb_enter(LBS_DEB_ASSOC);
priv->adhoccreate = 1; priv->adhoccreate = 1;
if (priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) { if (priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) {
lbs_deb_join("AdhocStart: Short preamble\n"); lbs_deb_join("AdhocStart: Short preamble\n");
priv->preamble = CMD_TYPE_SHORT_PREAMBLE; preamble = RADIO_PREAMBLE_SHORT;
} else {
lbs_deb_join("AdhocStart: Long preamble\n");
priv->preamble = CMD_TYPE_LONG_PREAMBLE;
} }
lbs_set_radio_control(priv); ret = lbs_set_radio(priv, preamble, 1);
if (ret)
goto out;
lbs_deb_join("AdhocStart: channel = %d\n", assoc_req->channel); lbs_deb_join("AdhocStart: channel = %d\n", assoc_req->channel);
lbs_deb_join("AdhocStart: band = %d\n", assoc_req->band); lbs_deb_join("AdhocStart: band = %d\n", assoc_req->band);
...@@ -162,6 +165,8 @@ static int lbs_start_adhoc_network(struct lbs_private *priv, ...@@ -162,6 +165,8 @@ static int lbs_start_adhoc_network(struct lbs_private *priv,
ret = lbs_prepare_and_send_command(priv, CMD_802_11_AD_HOC_START, ret = lbs_prepare_and_send_command(priv, CMD_802_11_AD_HOC_START,
0, CMD_OPTION_WAITFORRSP, 0, assoc_req); 0, CMD_OPTION_WAITFORRSP, 0, assoc_req);
out:
lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
return ret; return ret;
} }
......
...@@ -1289,41 +1289,47 @@ void lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd, ...@@ -1289,41 +1289,47 @@ void lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd,
priv->cur_cmd = NULL; priv->cur_cmd = NULL;
} }
int lbs_set_radio_control(struct lbs_private *priv) int lbs_set_radio(struct lbs_private *priv, u8 preamble, u8 radio_on)
{ {
int ret = 0;
struct cmd_ds_802_11_radio_control cmd; struct cmd_ds_802_11_radio_control cmd;
int ret = -EINVAL;
lbs_deb_enter(LBS_DEB_CMD); lbs_deb_enter(LBS_DEB_CMD);
cmd.hdr.size = cpu_to_le16(sizeof(cmd)); cmd.hdr.size = cpu_to_le16(sizeof(cmd));
cmd.action = cpu_to_le16(CMD_ACT_SET); cmd.action = cpu_to_le16(CMD_ACT_SET);
switch (priv->preamble) { /* Only v8 and below support setting the preamble */
case CMD_TYPE_SHORT_PREAMBLE: if (priv->fwrelease < 0x09000000) {
cmd.control = cpu_to_le16(SET_SHORT_PREAMBLE); switch (preamble) {
break; case RADIO_PREAMBLE_SHORT:
if (!(priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE))
case CMD_TYPE_LONG_PREAMBLE: goto out;
cmd.control = cpu_to_le16(SET_LONG_PREAMBLE); /* Fall through */
break; case RADIO_PREAMBLE_AUTO:
case RADIO_PREAMBLE_LONG:
cmd.control = cpu_to_le16(preamble);
break;
default:
goto out;
}
}
case CMD_TYPE_AUTO_PREAMBLE: if (radio_on)
default: cmd.control |= cpu_to_le16(0x1);
cmd.control = cpu_to_le16(SET_AUTO_PREAMBLE); else {
break; cmd.control &= cpu_to_le16(~0x1);
priv->txpower_cur = 0;
} }
if (priv->radioon) lbs_deb_cmd("RADIO_CONTROL: radio %s, preamble %d\n",
cmd.control |= cpu_to_le16(TURN_ON_RF); radio_on ? "ON" : "OFF", preamble);
else
cmd.control &= cpu_to_le16(~TURN_ON_RF);
lbs_deb_cmd("RADIO_SET: radio %d, preamble %d\n", priv->radioon, priv->radio_on = radio_on;
priv->preamble);
ret = lbs_cmd_with_response(priv, CMD_802_11_RADIO_CONTROL, &cmd); ret = lbs_cmd_with_response(priv, CMD_802_11_RADIO_CONTROL, &cmd);
out:
lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
return ret; return ret;
} }
......
...@@ -65,4 +65,6 @@ int lbs_get_tx_power(struct lbs_private *priv, s16 *curlevel, s16 *minlevel, ...@@ -65,4 +65,6 @@ int lbs_get_tx_power(struct lbs_private *priv, s16 *curlevel, s16 *minlevel,
s16 *maxlevel); s16 *maxlevel);
int lbs_set_tx_power(struct lbs_private *priv, s16 dbm); int lbs_set_tx_power(struct lbs_private *priv, s16 dbm);
int lbs_set_radio(struct lbs_private *priv, u8 preamble, u8 radio_on);
#endif /* _LBS_CMD_H */ #endif /* _LBS_CMD_H */
...@@ -34,7 +34,6 @@ int lbs_process_event(struct lbs_private *priv, u32 event); ...@@ -34,7 +34,6 @@ int lbs_process_event(struct lbs_private *priv, u32 event);
void lbs_queue_event(struct lbs_private *priv, u32 event); void lbs_queue_event(struct lbs_private *priv, u32 event);
void lbs_notify_command_response(struct lbs_private *priv, u8 resp_idx); void lbs_notify_command_response(struct lbs_private *priv, u8 resp_idx);
int lbs_set_radio_control(struct lbs_private *priv);
u32 lbs_fw_index_to_data_rate(u8 index); u32 lbs_fw_index_to_data_rate(u8 index);
u8 lbs_data_rate_to_fw_index(u32 rate); u8 lbs_data_rate_to_fw_index(u32 rate);
......
...@@ -293,8 +293,7 @@ struct lbs_private { ...@@ -293,8 +293,7 @@ struct lbs_private {
u16 nextSNRNF; u16 nextSNRNF;
u16 numSNRNF; u16 numSNRNF;
u8 radioon; u8 radio_on;
u32 preamble;
/** data rate stuff */ /** data rate stuff */
u8 cur_rate; u8 cur_rate;
......
...@@ -152,11 +152,6 @@ ...@@ -152,11 +152,6 @@
#define CMD_ACT_MAC_ALL_MULTICAST_ENABLE 0x0100 #define CMD_ACT_MAC_ALL_MULTICAST_ENABLE 0x0100
#define CMD_ACT_MAC_STRICT_PROTECTION_ENABLE 0x0400 #define CMD_ACT_MAC_STRICT_PROTECTION_ENABLE 0x0400
/* Define action or option for CMD_802_11_RADIO_CONTROL */
#define CMD_TYPE_AUTO_PREAMBLE 0x0001
#define CMD_TYPE_SHORT_PREAMBLE 0x0002
#define CMD_TYPE_LONG_PREAMBLE 0x0003
/* Event flags for CMD_802_11_SUBSCRIBE_EVENT */ /* Event flags for CMD_802_11_SUBSCRIBE_EVENT */
#define CMD_SUBSCRIBE_RSSI_LOW 0x0001 #define CMD_SUBSCRIBE_RSSI_LOW 0x0001
#define CMD_SUBSCRIBE_SNR_LOW 0x0002 #define CMD_SUBSCRIBE_SNR_LOW 0x0002
...@@ -165,13 +160,9 @@ ...@@ -165,13 +160,9 @@
#define CMD_SUBSCRIBE_RSSI_HIGH 0x0010 #define CMD_SUBSCRIBE_RSSI_HIGH 0x0010
#define CMD_SUBSCRIBE_SNR_HIGH 0x0020 #define CMD_SUBSCRIBE_SNR_HIGH 0x0020
#define TURN_ON_RF 0x01 #define RADIO_PREAMBLE_LONG 0x00
#define RADIO_ON 0x01 #define RADIO_PREAMBLE_SHORT 0x02
#define RADIO_OFF 0x00 #define RADIO_PREAMBLE_AUTO 0x04
#define SET_AUTO_PREAMBLE 0x05
#define SET_SHORT_PREAMBLE 0x03
#define SET_LONG_PREAMBLE 0x01
/* Define action or option for CMD_802_11_RF_CHANNEL */ /* Define action or option for CMD_802_11_RF_CHANNEL */
#define CMD_OPT_802_11_RF_CHANNEL_GET 0x00 #define CMD_OPT_802_11_RF_CHANNEL_GET 0x00
......
...@@ -1051,7 +1051,7 @@ static int lbs_init_adapter(struct lbs_private *priv) ...@@ -1051,7 +1051,7 @@ static int lbs_init_adapter(struct lbs_private *priv)
priv->mode = IW_MODE_INFRA; priv->mode = IW_MODE_INFRA;
priv->curbssparams.channel = DEFAULT_AD_HOC_CHANNEL; priv->curbssparams.channel = DEFAULT_AD_HOC_CHANNEL;
priv->mac_control = CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON; priv->mac_control = CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON;
priv->radioon = RADIO_ON; priv->radio_on = 1;
priv->enablehwauto = 1; priv->enablehwauto = 1;
priv->capability = WLAN_CAPABILITY_SHORT_PREAMBLE; priv->capability = WLAN_CAPABILITY_SHORT_PREAMBLE;
priv->psmode = LBS802_11POWERMODECAM; priv->psmode = LBS802_11POWERMODECAM;
......
...@@ -944,6 +944,11 @@ int lbs_set_scan(struct net_device *dev, struct iw_request_info *info, ...@@ -944,6 +944,11 @@ int lbs_set_scan(struct net_device *dev, struct iw_request_info *info,
lbs_deb_enter(LBS_DEB_WEXT); lbs_deb_enter(LBS_DEB_WEXT);
if (!priv->radio_on) {
ret = -EINVAL;
goto out;
}
if (!netif_running(dev)) { if (!netif_running(dev)) {
ret = -ENETDOWN; ret = -ENETDOWN;
goto out; goto out;
......
...@@ -120,34 +120,6 @@ static struct chan_freq_power *find_cfp_by_band_and_freq( ...@@ -120,34 +120,6 @@ static struct chan_freq_power *find_cfp_by_band_and_freq(
return cfp; return cfp;
} }
/**
* @brief Set Radio On/OFF
*
* @param priv A pointer to struct lbs_private structure
* @option Radio Option
* @return 0 --success, otherwise fail
*/
static int lbs_radio_ioctl(struct lbs_private *priv, u8 option)
{
int ret = 0;
lbs_deb_enter(LBS_DEB_WEXT);
if (priv->radioon != option) {
lbs_deb_wext("switching radio %s\n", option ? "on" : "off");
priv->radioon = option;
ret = lbs_prepare_and_send_command(priv,
CMD_802_11_RADIO_CONTROL,
CMD_ACT_SET,
CMD_OPTION_WAITFORRSP, 0, NULL);
}
lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
return ret;
}
/** /**
* @brief Copy active data rates based on adapter mode and status * @brief Copy active data rates based on adapter mode and status
* *
...@@ -420,26 +392,30 @@ static int lbs_get_txpow(struct net_device *dev, ...@@ -420,26 +392,30 @@ static int lbs_get_txpow(struct net_device *dev,
struct iw_request_info *info, struct iw_request_info *info,
struct iw_param *vwrq, char *extra) struct iw_param *vwrq, char *extra)
{ {
int ret = 0;
struct lbs_private *priv = dev->priv; struct lbs_private *priv = dev->priv;
s16 curlevel = 0; s16 curlevel = 0;
int ret = 0;
lbs_deb_enter(LBS_DEB_WEXT); lbs_deb_enter(LBS_DEB_WEXT);
if (!priv->radio_on) {
lbs_deb_wext("tx power off\n");
vwrq->value = 0;
vwrq->disabled = 1;
goto out;
}
ret = lbs_get_tx_power(priv, &curlevel, NULL, NULL); ret = lbs_get_tx_power(priv, &curlevel, NULL, NULL);
if (ret) if (ret)
goto out; goto out;
lbs_deb_wext("tx power level %d dbm\n", curlevel); lbs_deb_wext("tx power level %d dbm\n", curlevel);
priv->txpower_cur = curlevel; priv->txpower_cur = curlevel;
vwrq->value = curlevel; vwrq->value = curlevel;
vwrq->fixed = 1; vwrq->fixed = 1;
if (priv->radioon) { vwrq->disabled = 0;
vwrq->disabled = 0; vwrq->flags = IW_TXPOW_DBM;
vwrq->flags = IW_TXPOW_DBM;
} else
vwrq->disabled = 1;
out: out:
lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
...@@ -1839,13 +1815,12 @@ static int lbs_set_txpow(struct net_device *dev, struct iw_request_info *info, ...@@ -1839,13 +1815,12 @@ static int lbs_set_txpow(struct net_device *dev, struct iw_request_info *info,
lbs_deb_enter(LBS_DEB_WEXT); lbs_deb_enter(LBS_DEB_WEXT);
if (vwrq->disabled) { if (vwrq->disabled) {
lbs_radio_ioctl(priv, RADIO_OFF); lbs_set_radio(priv, RADIO_PREAMBLE_AUTO, 0);
goto out; goto out;
} }
if (vwrq->fixed == 0) { if (vwrq->fixed == 0) {
/* Auto power control */ /* Auto power control */
priv->preamble = CMD_TYPE_AUTO_PREAMBLE;
dbm = priv->txpower_max; dbm = priv->txpower_max;
} else { } else {
/* Userspace check in iwrange if it should use dBm or mW, /* Userspace check in iwrange if it should use dBm or mW,
...@@ -1867,7 +1842,12 @@ static int lbs_set_txpow(struct net_device *dev, struct iw_request_info *info, ...@@ -1867,7 +1842,12 @@ static int lbs_set_txpow(struct net_device *dev, struct iw_request_info *info,
} }
} }
lbs_radio_ioctl(priv, RADIO_ON); /* If the radio was off, turn it on */
if (!priv->radio_on) {
ret = lbs_set_radio(priv, RADIO_PREAMBLE_AUTO, 1);
if (ret)
goto out;
}
lbs_deb_wext("txpower set %d dBm\n", dbm); lbs_deb_wext("txpower set %d dBm\n", dbm);
...@@ -1925,6 +1905,11 @@ static int lbs_set_essid(struct net_device *dev, struct iw_request_info *info, ...@@ -1925,6 +1905,11 @@ static int lbs_set_essid(struct net_device *dev, struct iw_request_info *info,
lbs_deb_enter(LBS_DEB_WEXT); lbs_deb_enter(LBS_DEB_WEXT);
if (!priv->radio_on) {
ret = -EINVAL;
goto out;
}
/* Check the size of the string */ /* Check the size of the string */
if (in_ssid_len > IW_ESSID_MAX_SIZE) { if (in_ssid_len > IW_ESSID_MAX_SIZE) {
ret = -E2BIG; ret = -E2BIG;
...@@ -2002,6 +1987,11 @@ static int lbs_mesh_set_essid(struct net_device *dev, ...@@ -2002,6 +1987,11 @@ static int lbs_mesh_set_essid(struct net_device *dev,
lbs_deb_enter(LBS_DEB_WEXT); lbs_deb_enter(LBS_DEB_WEXT);
if (!priv->radio_on) {
ret = -EINVAL;
goto out;
}
/* Check the size of the string */ /* Check the size of the string */
if (dwrq->length > IW_ESSID_MAX_SIZE) { if (dwrq->length > IW_ESSID_MAX_SIZE) {
ret = -E2BIG; ret = -E2BIG;
...@@ -2043,6 +2033,9 @@ static int lbs_set_wap(struct net_device *dev, struct iw_request_info *info, ...@@ -2043,6 +2033,9 @@ static int lbs_set_wap(struct net_device *dev, struct iw_request_info *info,
lbs_deb_enter(LBS_DEB_WEXT); lbs_deb_enter(LBS_DEB_WEXT);
if (!priv->radio_on)
return -EINVAL;
if (awrq->sa_family != ARPHRD_ETHER) if (awrq->sa_family != ARPHRD_ETHER)
return -EINVAL; return -EINVAL;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment