diff options
author | David S. Miller <davem@davemloft.net> | 2008-08-29 14:02:13 -0700 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-08-29 14:02:13 -0700 |
commit | 143b11c03cd42f2284efe5128afc057d8fc86c78 (patch) | |
tree | 8186830c461b7933c26cdd00b69e4c737c5c88e7 /drivers/net/wireless/libertas | |
parent | af01d537463714e36e2c96d2da35902b76cd6827 (diff) | |
parent | 18c8adeb0244f823ba78a51e23f813fe68bc3c54 (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
Diffstat (limited to 'drivers/net/wireless/libertas')
-rw-r--r-- | drivers/net/wireless/libertas/assoc.c | 744 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/assoc.h | 18 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/cmd.c | 147 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/cmd.h | 6 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/cmdresp.c | 33 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/decl.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/dev.h | 7 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/host.h | 26 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/hostcmd.h | 50 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/main.c | 21 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/scan.c | 5 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/wext.c | 148 |
12 files changed, 541 insertions, 665 deletions
diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index a267d6e65f0..4ddf44b2758 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c @@ -8,6 +8,7 @@ #include "scan.h" #include "cmd.h" +static int lbs_adhoc_post(struct lbs_private *priv, struct cmd_header *resp); static const u8 bssid_any[ETH_ALEN] __attribute__ ((aligned (2))) = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; @@ -20,12 +21,88 @@ static const u8 bssid_off[ETH_ALEN] __attribute__ ((aligned (2))) = #define CAPINFO_MASK (~(0xda00)) +/** + * @brief This function finds common rates between rates and card rates. + * + * It will fill common rates in rates as output if found. + * + * NOTE: Setting the MSB of the basic rates need to be taken + * care, either before or after calling this function + * + * @param priv A pointer to struct lbs_private structure + * @param rates the buffer which keeps input and output + * @param rates_size the size of rate1 buffer; new size of buffer on return + * + * @return 0 on success, or -1 on error + */ +static int get_common_rates(struct lbs_private *priv, + u8 *rates, + u16 *rates_size) +{ + u8 *card_rates = lbs_bg_rates; + size_t num_card_rates = sizeof(lbs_bg_rates); + int ret = 0, i, j; + u8 tmp[30]; + size_t tmp_size = 0; + + /* For each rate in card_rates that exists in rate1, copy to tmp */ + for (i = 0; card_rates[i] && (i < num_card_rates); i++) { + for (j = 0; rates[j] && (j < *rates_size); j++) { + if (rates[j] == card_rates[i]) + tmp[tmp_size++] = card_rates[i]; + } + } + + lbs_deb_hex(LBS_DEB_JOIN, "AP rates ", rates, *rates_size); + lbs_deb_hex(LBS_DEB_JOIN, "card rates ", card_rates, num_card_rates); + lbs_deb_hex(LBS_DEB_JOIN, "common rates", tmp, tmp_size); + lbs_deb_join("TX data rate 0x%02x\n", priv->cur_rate); + + if (!priv->enablehwauto) { + for (i = 0; i < tmp_size; i++) { + if (tmp[i] == priv->cur_rate) + goto done; + } + lbs_pr_alert("Previously set fixed data rate %#x isn't " + "compatible with the network.\n", priv->cur_rate); + ret = -1; + goto done; + } + ret = 0; + +done: + memset(rates, 0, *rates_size); + *rates_size = min_t(int, tmp_size, *rates_size); + memcpy(rates, tmp, *rates_size); + return ret; +} + + +/** + * @brief Sets the MSB on basic rates as the firmware requires + * + * Scan through an array and set the MSB for basic data rates. + * + * @param rates buffer of data rates + * @param len size of buffer + */ +static void lbs_set_basic_rate_flags(u8 *rates, size_t len) +{ + int i; + + for (i = 0; i < len; i++) { + if (rates[i] == 0x02 || rates[i] == 0x04 || + rates[i] == 0x0b || rates[i] == 0x16) + rates[i] |= 0x80; + } +} + /** * @brief Associate to a specific BSS discovered in a scan * * @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 */ @@ -33,29 +110,29 @@ static int lbs_associate(struct lbs_private *priv, struct assoc_request *assoc_req) { int ret; + u8 preamble = RADIO_PREAMBLE_LONG; lbs_deb_enter(LBS_DEB_ASSOC); ret = lbs_prepare_and_send_command(priv, CMD_802_11_AUTHENTICATE, 0, CMD_OPTION_WAITFORRSP, 0, assoc_req->bss.bssid); - 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) && (assoc_req->bss.capability & WLAN_CAPABILITY_SHORT_PREAMBLE)) - priv->preamble = CMD_TYPE_SHORT_PREAMBLE; - else - priv->preamble = CMD_TYPE_LONG_PREAMBLE; + preamble = RADIO_PREAMBLE_SHORT; - 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, 0, CMD_OPTION_WAITFORRSP, 0, assoc_req); -done: +out: lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); return ret; } @@ -64,17 +141,22 @@ done: * @brief Join an adhoc network found in a previous scan * * @param priv A pointer to struct lbs_private structure - * @param pbssdesc Pointer to a BSS descriptor found in a previous scan - * to attempt to join + * @param assoc_req The association request describing the BSS to join * - * @return 0--success, -1--fail + * @return 0 on success, error on failure */ -static int lbs_join_adhoc_network(struct lbs_private *priv, +static int lbs_adhoc_join(struct lbs_private *priv, struct assoc_request *assoc_req) { + struct cmd_ds_802_11_ad_hoc_join cmd; struct bss_descriptor *bss = &assoc_req->bss; + u8 preamble = RADIO_PREAMBLE_LONG; + DECLARE_MAC_BUF(mac); + u16 ratesize = 0; int ret = 0; + lbs_deb_enter(LBS_DEB_ASSOC); + lbs_deb_join("current SSID '%s', ssid length %u\n", escape_essid(priv->curbssparams.ssid, priv->curbssparams.ssid_len), @@ -106,29 +188,106 @@ static int lbs_join_adhoc_network(struct lbs_private *priv, goto out; } - /* Use shortpreamble only when both creator and card supports - short preamble */ - if (!(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 { + /* Use short preamble only when both the BSS and firmware support it */ + if ((priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) && + (bss->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)) { 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: band = %c\n", assoc_req->band); priv->adhoccreate = 0; + priv->curbssparams.channel = bss->channel; - ret = lbs_prepare_and_send_command(priv, CMD_802_11_AD_HOC_JOIN, - 0, CMD_OPTION_WAITFORRSP, - OID_802_11_SSID, assoc_req); + /* Build the join command */ + memset(&cmd, 0, sizeof(cmd)); + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); + + cmd.bss.type = CMD_BSS_TYPE_IBSS; + cmd.bss.beaconperiod = cpu_to_le16(bss->beaconperiod); + + memcpy(&cmd.bss.bssid, &bss->bssid, ETH_ALEN); + memcpy(&cmd.bss.ssid, &bss->ssid, bss->ssid_len); + + memcpy(&cmd.bss.phyparamset, &bss->phyparamset, + sizeof(union ieeetypes_phyparamset)); + + memcpy(&cmd.bss.ssparamset, &bss->ssparamset, + sizeof(union IEEEtypes_ssparamset)); + + cmd.bss.capability = cpu_to_le16(bss->capability & CAPINFO_MASK); + lbs_deb_join("ADHOC_J_CMD: tmpcap=%4X CAPINFO_MASK=%4X\n", + bss->capability, CAPINFO_MASK); + + /* information on BSSID descriptor passed to FW */ + lbs_deb_join("ADHOC_J_CMD: BSSID = %s, SSID = '%s'\n", + print_mac(mac, cmd.bss.bssid), cmd.bss.ssid); + + /* Only v8 and below support setting these */ + if (priv->fwrelease < 0x09000000) { + /* failtimeout */ + cmd.failtimeout = cpu_to_le16(MRVDRV_ASSOCIATION_TIME_OUT); + /* probedelay */ + cmd.probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME); + } + + /* Copy Data rates from the rates recorded in scan response */ + memset(cmd.bss.rates, 0, sizeof(cmd.bss.rates)); + ratesize = min_t(u16, sizeof(cmd.bss.rates), MAX_RATES); + memcpy(cmd.bss.rates, bss->rates, ratesize); + if (get_common_rates(priv, cmd.bss.rates, &ratesize)) { + lbs_deb_join("ADHOC_JOIN: get_common_rates returned error.\n"); + ret = -1; + goto out; + } + + /* Copy the ad-hoc creation rates into Current BSS state structure */ + memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates)); + memcpy(&priv->curbssparams.rates, cmd.bss.rates, ratesize); + + /* Set MSB on basic rates as the firmware requires, but _after_ + * copying to current bss rates. + */ + lbs_set_basic_rate_flags(cmd.bss.rates, ratesize); + + cmd.bss.ssparamset.ibssparamset.atimwindow = cpu_to_le16(bss->atimwindow); + + if (assoc_req->secinfo.wep_enabled) { + u16 tmp = le16_to_cpu(cmd.bss.capability); + tmp |= WLAN_CAPABILITY_PRIVACY; + cmd.bss.capability = cpu_to_le16(tmp); + } + + if (priv->psmode == LBS802_11POWERMODEMAX_PSP) { + __le32 local_ps_mode = cpu_to_le32(LBS802_11POWERMODECAM); + + /* wake up first */ + ret = lbs_prepare_and_send_command(priv, CMD_802_11_PS_MODE, + CMD_ACT_SET, 0, 0, + &local_ps_mode); + if (ret) { + ret = -1; + goto out; + } + } + + if (lbs_parse_dnld_countryinfo_11d(priv, bss)) { + ret = -1; + goto out; + } + + ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_JOIN, &cmd); + if (ret == 0) + ret = lbs_adhoc_post(priv, (struct cmd_header *) &cmd); out: + lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); return ret; } @@ -136,39 +295,131 @@ out: * @brief Start an Adhoc Network * * @param priv A pointer to struct lbs_private structure - * @param adhocssid The ssid of the Adhoc Network - * @return 0--success, -1--fail + * @param assoc_req The association request describing the BSS to start + * + * @return 0 on success, error on failure */ -static int lbs_start_adhoc_network(struct lbs_private *priv, +static int lbs_adhoc_start(struct lbs_private *priv, struct assoc_request *assoc_req) { + struct cmd_ds_802_11_ad_hoc_start cmd; + u8 preamble = RADIO_PREAMBLE_LONG; + size_t ratesize = 0; + u16 tmpcap = 0; int ret = 0; - priv->adhoccreate = 1; + lbs_deb_enter(LBS_DEB_ASSOC); if (priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) { - lbs_deb_join("AdhocStart: Short preamble\n"); - priv->preamble = CMD_TYPE_SHORT_PREAMBLE; - } else { - lbs_deb_join("AdhocStart: Long preamble\n"); - priv->preamble = CMD_TYPE_LONG_PREAMBLE; + lbs_deb_join("ADHOC_START: Will use short preamble\n"); + preamble = RADIO_PREAMBLE_SHORT; } - 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: band = %d\n", assoc_req->band); + /* Build the start command */ + memset(&cmd, 0, sizeof(cmd)); + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); - ret = lbs_prepare_and_send_command(priv, CMD_802_11_AD_HOC_START, - 0, CMD_OPTION_WAITFORRSP, 0, assoc_req); + memcpy(cmd.ssid, assoc_req->ssid, assoc_req->ssid_len); + + lbs_deb_join("ADHOC_START: SSID '%s', ssid length %u\n", + escape_essid(assoc_req->ssid, assoc_req->ssid_len), + assoc_req->ssid_len); + cmd.bsstype = CMD_BSS_TYPE_IBSS; + + if (priv->beacon_period == 0) + priv->beacon_period = MRVDRV_BEACON_INTERVAL; + cmd.beaconperiod = cpu_to_le16(priv->beacon_period); + + WARN_ON(!assoc_req->channel); + + /* set Physical parameter set */ + cmd.phyparamset.dsparamset.elementid = MFIE_TYPE_DS_SET; + cmd.phyparamset.dsparamset.len = 1; + cmd.phyparamset.dsparamset.currentchan = assoc_req->channel; + + /* set IBSS parameter set */ + cmd.ssparamset.ibssparamset.elementid = MFIE_TYPE_IBSS_SET; + cmd.ssparamset.ibssparamset.len = 2; + cmd.ssparamset.ibssparamset.atimwindow = 0; + + /* set capability info */ + tmpcap = WLAN_CAPABILITY_IBSS; + if (assoc_req->secinfo.wep_enabled) { + lbs_deb_join("ADHOC_START: WEP enabled, setting privacy on\n"); + tmpcap |= WLAN_CAPABILITY_PRIVACY; + } else + lbs_deb_join("ADHOC_START: WEP disabled, setting privacy off\n"); + + cmd.capability = cpu_to_le16(tmpcap); + + /* Only v8 and below support setting probe delay */ + if (priv->fwrelease < 0x09000000) + cmd.probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME); + + ratesize = min(sizeof(cmd.rates), sizeof(lbs_bg_rates)); + memcpy(cmd.rates, lbs_bg_rates, ratesize); + + /* Copy the ad-hoc creating rates into Current BSS state structure */ + memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates)); + memcpy(&priv->curbssparams.rates, &cmd.rates, ratesize); + + /* Set MSB on basic rates as the firmware requires, but _after_ + * copying to current bss rates. + */ + lbs_set_basic_rate_flags(cmd.rates, ratesize); + + lbs_deb_join("ADHOC_START: rates=%02x %02x %02x %02x\n", + cmd.rates[0], cmd.rates[1], cmd.rates[2], cmd.rates[3]); + + if (lbs_create_dnld_countryinfo_11d(priv)) { + lbs_deb_join("ADHOC_START: dnld_countryinfo_11d failed\n"); + ret = -1; + goto out; + } + + lbs_deb_join("ADHOC_START: Starting Ad-Hoc BSS on channel %d, band %d\n", + assoc_req->channel, assoc_req->band); + + priv->adhoccreate = 1; + priv->mode = IW_MODE_ADHOC; + + ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_START, &cmd); + if (ret == 0) + ret = lbs_adhoc_post(priv, (struct cmd_header *) &cmd); + +out: + lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); return ret; } -int lbs_stop_adhoc_network(struct lbs_private *priv) +/** + * @brief Stop and Ad-Hoc network and exit Ad-Hoc mode + * + * @param priv A pointer to struct lbs_private structure + * @return 0 on success, or an error + */ +int lbs_adhoc_stop(struct lbs_private *priv) { - return lbs_prepare_and_send_command(priv, CMD_802_11_AD_HOC_STOP, - 0, CMD_OPTION_WAITFORRSP, 0, NULL); + struct cmd_ds_802_11_ad_hoc_stop cmd; + int ret; + + lbs_deb_enter(LBS_DEB_JOIN); + + memset(&cmd, 0, sizeof (cmd)); + cmd.hdr.size = cpu_to_le16 (sizeof (cmd)); + + ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_STOP, &cmd); + + /* Clean up everything even if there was an error */ + lbs_mac_event_disconnected(priv); + + lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); + return ret; } static inline int match_bss_no_security(struct lbs_802_11_security *secinfo, @@ -480,14 +731,14 @@ static int assoc_helper_essid(struct lbs_private *priv, if (bss != NULL) { lbs_deb_assoc("SSID found, will join\n"); memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor)); - lbs_join_adhoc_network(priv, assoc_req); + lbs_adhoc_join(priv, assoc_req); } else { /* else send START command */ lbs_deb_assoc("SSID not found, creating adhoc network\n"); memcpy(&assoc_req->bss.ssid, &assoc_req->ssid, IW_ESSID_MAX_SIZE); assoc_req->bss.ssid_len = assoc_req->ssid_len; - lbs_start_adhoc_network(priv, assoc_req); + lbs_adhoc_start(priv, assoc_req); } } @@ -520,7 +771,7 @@ static int assoc_helper_bssid(struct lbs_private *priv, ret = lbs_associate(priv, assoc_req); lbs_deb_assoc("ASSOC: lbs_associate(bssid) returned %d\n", ret); } else if (assoc_req->mode == IW_MODE_ADHOC) { - lbs_join_adhoc_network(priv, assoc_req); + lbs_adhoc_join(priv, assoc_req); } out: @@ -1029,7 +1280,9 @@ void lbs_association_worker(struct work_struct *work) */ if (priv->mode == IW_MODE_INFRA) { if (should_deauth_infrastructure(priv, assoc_req)) { - ret = lbs_send_deauthentication(priv); + ret = lbs_cmd_80211_deauthenticate(priv, + priv->curbssparams.bssid, + WLAN_REASON_DEAUTH_LEAVING); if (ret) { lbs_deb_assoc("Deauthentication due to new " "configuration request failed: %d\n", @@ -1038,7 +1291,7 @@ void lbs_association_worker(struct work_struct *work) } } else if (priv->mode == IW_MODE_ADHOC) { if (should_stop_adhoc(priv, assoc_req)) { - ret = lbs_stop_adhoc_network(priv); + ret = lbs_adhoc_stop(priv); if (ret) { lbs_deb_assoc("Teardown of AdHoc network due to " "new configuration request failed: %d\n", @@ -1214,94 +1467,6 @@ struct assoc_request *lbs_get_association_request(struct lbs_private *priv) /** - * @brief This function finds common rates between rate1 and card rates. - * - * It will fill common rates in rate1 as output if found. - * - * NOTE: Setting the MSB of the basic rates need to be taken - * care, either before or after calling this function - * - * @param priv A pointer to struct lbs_private structure - * @param rate1 the buffer which keeps input and output - * @param rate1_size the size of rate1 buffer; new size of buffer on return - * - * @return 0 or -1 - */ -static int get_common_rates(struct lbs_private *priv, - u8 *rates, - u16 *rates_size) -{ - u8 *card_rates = lbs_bg_rates; - size_t num_card_rates = sizeof(lbs_bg_rates); - int ret = 0, i, j; - u8 tmp[30]; - size_t tmp_size = 0; - - /* For each rate in card_rates that exists in rate1, copy to tmp */ - for (i = 0; card_rates[i] && (i < num_card_rates); i++) { - for (j = 0; rates[j] && (j < *rates_size); j++) { - if (rates[j] == card_rates[i]) - tmp[tmp_size++] = card_rates[i]; - } - } - - lbs_deb_hex(LBS_DEB_JOIN, "AP rates ", rates, *rates_size); - lbs_deb_hex(LBS_DEB_JOIN, "card rates ", card_rates, num_card_rates); - lbs_deb_hex(LBS_DEB_JOIN, "common rates", tmp, tmp_size); - lbs_deb_join("TX data rate 0x%02x\n", priv->cur_rate); - - if (!priv->enablehwauto) { - for (i = 0; i < tmp_size; i++) { - if (tmp[i] == priv->cur_rate) - goto done; - } - lbs_pr_alert("Previously set fixed data rate %#x isn't " - "compatible with the network.\n", priv->cur_rate); - ret = -1; - goto done; - } - ret = 0; - -done: - memset(rates, 0, *rates_size); - *rates_size = min_t(int, tmp_size, *rates_size); - memcpy(rates, tmp, *rates_size); - return ret; -} - - -/** - * @brief Sets the MSB on basic rates as the firmware requires - * - * Scan through an array and set the MSB for basic data rates. - * - * @param rates buffer of data rates - * @param len size of buffer - */ -static void lbs_set_basic_rate_flags(u8 *rates, size_t len) -{ - int i; - - for (i = 0; i < len; i++) { - if (rates[i] == 0x02 || rates[i] == 0x04 || - rates[i] == 0x0b || rates[i] == 0x16) - rates[i] |= 0x80; - } -} - -/** - * @brief Send Deauthentication Request - * - * @param priv A pointer to struct lbs_private structure - * @return 0--success, -1--fail - */ -int lbs_send_deauthentication(struct lbs_private *priv) -{ - return lbs_prepare_and_send_command(priv, CMD_802_11_DEAUTHENTICATE, - 0, CMD_OPTION_WAITFORRSP, 0, NULL); -} - -/** * @brief This function prepares command of authenticate. * * @param priv A pointer to struct lbs_private structure @@ -1353,26 +1518,37 @@ out: return ret; } -int lbs_cmd_80211_deauthenticate(struct lbs_private *priv, - struct cmd_ds_command *cmd) +/** + * @brief Deauthenticate from a specific BSS + * + * @param priv A pointer to struct lbs_private structure + * @param bssid The specific BSS to deauthenticate from + * @param reason The 802.11 sec. 7.3.1.7 Reason Code for deauthenticating + * + * @return 0 on success, error on failure + */ +int lbs_cmd_80211_deauthenticate(struct lbs_private *priv, u8 bssid[ETH_ALEN], + u16 reason) { - struct cmd_ds_802_11_deauthenticate *dauth = &cmd->params.deauth; + struct cmd_ds_802_11_deauthenticate cmd; + int ret; lbs_deb_enter(LBS_DEB_JOIN); - cmd->command = cpu_to_le16(CMD_802_11_DEAUTHENTICATE); - cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_deauthenticate) + - S_DS_GEN); + memset(&cmd, 0, sizeof(cmd)); + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); + memcpy(cmd.macaddr, &bssid[0], ETH_ALEN); + cmd.reasoncode = cpu_to_le16(reason); - /* set AP MAC address */ - memmove(dauth->macaddr, priv->curbssparams.bssid, ETH_ALEN); + ret = lbs_cmd_with_response(priv, CMD_802_11_DEAUTHENTICATE, &cmd); - /* Reason code 3 = Station is leaving */ -#define REASON_CODE_STA_LEAVING 3 - dauth->reasoncode = cpu_to_le16(REASON_CODE_STA_LEAVING); + /* Clean up everything even if there was an error; can't assume that + * we're still authenticated to the AP after trying to deauth. + */ + lbs_mac_event_disconnected(priv); lbs_deb_leave(LBS_DEB_JOIN); - return 0; + return ret; } int lbs_cmd_80211_associate(struct lbs_private *priv, @@ -1489,231 +1665,6 @@ done: return ret; } -int lbs_cmd_80211_ad_hoc_start(struct lbs_private *priv, - struct cmd_ds_command *cmd, void *pdata_buf) -{ - struct cmd_ds_802_11_ad_hoc_start *adhs = &cmd->params.ads; - int ret = 0; - int cmdappendsize = 0; - struct assoc_request *assoc_req = pdata_buf; - u16 tmpcap = 0; - size_t ratesize = 0; - - lbs_deb_enter(LBS_DEB_JOIN); - - if (!priv) { - ret = -1; - goto done; - } - - cmd->command = cpu_to_le16(CMD_802_11_AD_HOC_START); - - /* - * Fill in the parameters for 2 data structures: - * 1. cmd_ds_802_11_ad_hoc_start command - * 2. priv->scantable[i] - * - * Driver will fill up SSID, bsstype,IBSS param, Physical Param, - * probe delay, and cap info. - * - * Firmware will fill up beacon period, DTIM, Basic rates - * and operational rates. - */ - - memset(adhs->ssid, 0, IW_ESSID_MAX_SIZE); - memcpy(adhs->ssid, assoc_req->ssid, assoc_req->ssid_len); - - lbs_deb_join("ADHOC_S_CMD: SSID '%s', ssid length %u\n", - escape_essid(assoc_req->ssid, assoc_req->ssid_len), - assoc_req->ssid_len); - - /* set the BSS type */ - adhs->bsstype = CMD_BSS_TYPE_IBSS; - priv->mode = IW_MODE_ADHOC; - if (priv->beacon_period == 0) - priv->beacon_period = MRVDRV_BEACON_INTERVAL; - adhs->beaconperiod = cpu_to_le16(priv->beacon_period); - - /* set Physical param set */ -#define DS_PARA_IE_ID 3 -#define DS_PARA_IE_LEN 1 - - adhs->phyparamset.dsparamset.elementid = DS_PARA_IE_ID; - adhs->phyparamset.dsparamset.len = DS_PARA_IE_LEN; - - WARN_ON(!assoc_req->channel); - - lbs_deb_join("ADHOC_S_CMD: Creating ADHOC on channel %d\n", - assoc_req->channel); - - adhs->phyparamset.dsparamset.currentchan = assoc_req->channel; - - /* set IBSS param set */ -#define IBSS_PARA_IE_ID 6 -#define IBSS_PARA_IE_LEN 2 - - adhs->ssparamset.ibssparamset.elementid = IBSS_PARA_IE_ID; - adhs->ssparamset.ibssparamset.len = IBSS_PARA_IE_LEN; - adhs->ssparamset.ibssparamset.atimwindow = 0; - - /* set capability info */ - tmpcap = WLAN_CAPABILITY_IBSS; - if (assoc_req->secinfo.wep_enabled) { - lbs_deb_join("ADHOC_S_CMD: WEP enabled, " - "setting privacy on\n"); - tmpcap |= WLAN_CAPABILITY_PRIVACY; - } else { - lbs_deb_join("ADHOC_S_CMD: WEP disabled, " - "setting privacy off\n"); - } - adhs->capability = cpu_to_le16(tmpcap); - - /* probedelay */ - adhs->probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME); - - memset(adhs->rates, 0, sizeof(adhs->rates)); - ratesize = min(sizeof(adhs->rates), sizeof(lbs_bg_rates)); - memcpy(adhs->rates, lbs_bg_rates, ratesize); - - /* Copy the ad-hoc creating rates into Current BSS state structure */ - memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates)); - memcpy(&priv->curbssparams.rates, &adhs->rates, ratesize); - - /* Set MSB on basic rates as the firmware requires, but _after_ - * copying to current bss rates. - */ - lbs_set_basic_rate_flags(adhs->rates, ratesize); - - lbs_deb_join("ADHOC_S_CMD: rates=%02x %02x %02x %02x \n", - adhs->rates[0], adhs->rates[1], adhs->rates[2], adhs->rates[3]); - - lbs_deb_join("ADHOC_S_CMD: AD HOC Start command is ready\n"); - - if (lbs_create_dnld_countryinfo_11d(priv)) { - lbs_deb_join("ADHOC_S_CMD: dnld_countryinfo_11d failed\n"); - ret = -1; - goto done; - } - - cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_ad_hoc_start) + - S_DS_GEN + cmdappendsize); - - ret = 0; -done: - lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret); - return ret; -} - -int lbs_cmd_80211_ad_hoc_stop(struct cmd_ds_command *cmd) -{ - cmd->command = cpu_to_le16(CMD_802_11_AD_HOC_STOP); - cmd->size = cpu_to_le16(S_DS_GEN); - - return 0; -} - -int lbs_cmd_80211_ad_hoc_join(struct lbs_private *priv, - struct cmd_ds_command *cmd, void *pdata_buf) -{ - struct cmd_ds_802_11_ad_hoc_join *join_cmd = &cmd->params.adj; - struct assoc_request *assoc_req = pdata_buf; - struct bss_descriptor *bss = &assoc_req->bss; - int cmdappendsize = 0; - int ret = 0; - u16 ratesize = 0; - DECLARE_MAC_BUF(mac); - - lbs_deb_enter(LBS_DEB_JOIN); - - cmd->command = cpu_to_le16(CMD_802_11_AD_HOC_JOIN); - - join_cmd->bss.type = CMD_BSS_TYPE_IBSS; - join_cmd->bss.beaconperiod = cpu_to_le16(bss->beaconperiod); - - memcpy(&join_cmd->bss.bssid, &bss->bssid, ETH_ALEN); - memcpy(&join_cmd->bss.ssid, &bss->ssid, bss->ssid_len); - - memcpy(&join_cmd->bss.phyparamset, &bss->phyparamset, - sizeof(union ieeetypes_phyparamset)); - - memcpy(&join_cmd->bss.ssparamset, &bss->ssparamset, - sizeof(union IEEEtypes_ssparamset)); - - join_cmd->bss.capability = cpu_to_le16(bss->capability & CAPINFO_MASK); - lbs_deb_join("ADHOC_J_CMD: tmpcap=%4X CAPINFO_MASK=%4X\n", - bss->capability, CAPINFO_MASK); - - /* information on BSSID descriptor passed to FW */ - lbs_deb_join( - "ADHOC_J_CMD: BSSID = %s, SSID = '%s'\n", - print_mac(mac, join_cmd->bss.bssid), - join_cmd->bss.ssid); - - /* failtimeout */ - join_cmd->failtimeout = cpu_to_le16(MRVDRV_ASSOCIATION_TIME_OUT); - - /* probedelay */ - join_cmd->probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME); - - priv->curbssparams.channel = bss->channel; - - /* Copy Data rates from the rates recorded in scan response */ - memset(join_cmd->bss.rates, 0, sizeof(join_cmd->bss.rates)); - ratesize = min_t(u16, sizeof(join_cmd->bss.rates), MAX_RATES); - memcpy(join_cmd->bss.rates, bss->rates, ratesize); - if (get_common_rates(priv, join_cmd->bss.rates, &ratesize)) { - lbs_deb_join("ADHOC_J_CMD: get_common_rates returns error.\n"); - ret = -1; - goto done; - } - - /* Copy the ad-hoc creating rates into Current BSS state structure */ - memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates)); - memcpy(&priv->curbssparams.rates, join_cmd->bss.rates, ratesize); - - /* Set MSB on basic rates as the firmware requires, but _after_ - * copying to current bss rates. - */ - lbs_set_basic_rate_flags(join_cmd->bss.rates, ratesize); - - join_cmd->bss.ssparamset.ibssparamset.atimwindow = - cpu_to_le16(bss->atimwindow); - - if (assoc_req->secinfo.wep_enabled) { - u16 tmp = le16_to_cpu(join_cmd->bss.capability); - tmp |= WLAN_CAPABILITY_PRIVACY; - join_cmd->bss.capability = cpu_to_le16(tmp); - } - - if (priv->psmode == LBS802_11POWERMODEMAX_PSP) { - /* wake up first */ - __le32 Localpsmode; - - Localpsmode = cpu_to_le32(LBS802_11POWERMODECAM); - ret = lbs_prepare_and_send_command(priv, - CMD_802_11_PS_MODE, - CMD_ACT_SET, - 0, 0, &Localpsmode); - - if (ret) { - ret = -1; - goto done; - } - } - - if (lbs_parse_dnld_countryinfo_11d(priv, bss)) { - ret = -1; - goto done; - } - - cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_ad_hoc_join) + - S_DS_GEN + cmdappendsize); - -done: - lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret); - return ret; -} - int lbs_ret_80211_associate(struct lbs_private *priv, struct cmd_ds_command *resp) { @@ -1815,34 +1766,19 @@ done: return ret; } -int lbs_ret_80211_disassociate(struct lbs_private *priv) -{ - lbs_deb_enter(LBS_DEB_JOIN); - - lbs_mac_event_disconnected(priv); - - lbs_deb_leave(LBS_DEB_JOIN); - return 0; -} - -int lbs_ret_80211_ad_hoc_start(struct lbs_private *priv, - struct cmd_ds_command *resp) +static int lbs_adhoc_post(struct lbs_private *priv, struct cmd_header *resp) { int ret = 0; u16 command = le16_to_cpu(resp->command); u16 result = le16_to_cpu(resp->result); - struct cmd_ds_802_11_ad_hoc_result *padhocresult; + struct cmd_ds_802_11_ad_hoc_result *adhoc_resp; union iwreq_data wrqu; struct bss_descriptor *bss; DECLARE_MAC_BUF(mac); lbs_deb_enter(LBS_DEB_JOIN); - padhocresult = &resp->params.result; - - lbs_deb_join("ADHOC_RESP: size = %d\n", le16_to_cpu(resp->size)); - lbs_deb_join("ADHOC_RESP: command = %x\n", command); - lbs_deb_join("ADHOC_RESP: result = %x\n", result); + adhoc_resp = (struct cmd_ds_802_11_ad_hoc_result *) resp; if (!priv->in_progress_assoc_req) { lbs_deb_join("ADHOC_RESP: no in-progress association " @@ -1856,26 +1792,19 @@ int lbs_ret_80211_ad_hoc_start(struct lbs_private *priv, * Join result code 0 --> SUCCESS */ if (result) { - lbs_deb_join("ADHOC_RESP: failed\n"); + lbs_deb_join("ADHOC_RESP: failed (result 0x%X)\n", result); if (priv->connect_status == LBS_CONNECTED) lbs_mac_event_disconnected(priv); ret = -1; goto done; } - /* - * Now the join cmd should be successful - * If BSSID has changed use SSID to compare instead of BSSID - */ - lbs_deb_join("ADHOC_RESP: associated to '%s'\n", - escape_essid(bss->ssid, bss->ssid_len)); - /* Send a Media Connected event, according to the Spec */ priv->connect_status = LBS_CONNECTED; if (command == CMD_RET(CMD_802_11_AD_HOC_START)) { /* Update the created network descriptor with the new BSSID */ - memcpy(bss->bssid, padhocresult->bssid, ETH_ALEN); + memcpy(bss->bssid, adhoc_resp->bssid, ETH_ALEN); } /* Set the BSSID from the joined/started descriptor */ @@ -1894,22 +1823,13 @@ int lbs_ret_80211_ad_hoc_start(struct lbs_private *priv, wrqu.ap_addr.sa_family = ARPHRD_ETHER; wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); - lbs_deb_join("ADHOC_RESP: - Joined/Started Ad Hoc\n"); - lbs_deb_join("ADHOC_RESP: channel = %d\n", priv->curbssparams.channel); - lbs_deb_join("ADHOC_RESP: BSSID = %s\n", - print_mac(mac, padhocresult->bssid)); + lbs_deb_join("ADHOC_RESP: Joined/started '%s', BSSID %s, channel %d\n", + escape_essid(bss->ssid, bss->ssid_len), + print_mac(mac, priv->curbssparams.bssid), + priv->curbssparams.channel); done: lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret); return ret; } -int lbs_ret_80211_ad_hoc_stop(struct lbs_private *priv) -{ - lbs_deb_enter(LBS_DEB_JOIN); - - lbs_mac_event_disconnected(priv); - - lbs_deb_leave(LBS_DEB_JOIN); - return 0; -} diff --git a/drivers/net/wireless/libertas/assoc.h b/drivers/net/wireless/libertas/assoc.h index c516fbe518f..8b7336dd02a 100644 --- a/drivers/net/wireless/libertas/assoc.h +++ b/drivers/net/wireless/libertas/assoc.h @@ -12,28 +12,18 @@ struct cmd_ds_command; int lbs_cmd_80211_authenticate(struct lbs_private *priv, struct cmd_ds_command *cmd, void *pdata_buf); -int lbs_cmd_80211_ad_hoc_join(struct lbs_private *priv, - struct cmd_ds_command *cmd, - void *pdata_buf); -int lbs_cmd_80211_ad_hoc_stop(struct cmd_ds_command *cmd); -int lbs_cmd_80211_ad_hoc_start(struct lbs_private *priv, - struct cmd_ds_command *cmd, - void *pdata_buf); + +int lbs_adhoc_stop(struct lbs_private *priv); + int lbs_cmd_80211_deauthenticate(struct lbs_private *priv, - struct cmd_ds_command *cmd); + u8 bssid[ETH_ALEN], u16 reason); int lbs_cmd_80211_associate(struct lbs_private *priv, struct cmd_ds_command *cmd, void *pdata_buf); int lbs_ret_80211_ad_hoc_start(struct lbs_private *priv, struct cmd_ds_command *resp); -int lbs_ret_80211_ad_hoc_stop(struct lbs_private *priv); -int lbs_ret_80211_disassociate(struct lbs_private *priv); int lbs_ret_80211_associate(struct lbs_private *priv, struct cmd_ds_command *resp); -int lbs_stop_adhoc_network(struct lbs_private *priv); - -int lbs_send_deauthentication(struct lbs_private *priv); - #endif /* _LBS_ASSOC_H */ diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index af5fd709887..802547e7967 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -614,47 +614,67 @@ static int lbs_cmd_802_11_snmp_mib(struct lbs_private *priv, return 0; } -static int lbs_cmd_802_11_rf_tx_power(struct cmd_ds_command *cmd, - u16 cmd_action, void *pdata_buf) +/** + * @brief Get the min, max, and current TX power + * + * @param priv A pointer to struct lbs_private structure + * @param curlevel Current power level in dBm + * @param minlevel Minimum supported power level in dBm (optional) + * @param maxlevel Maximum supported power level in dBm (optional) + * + * @return 0 on success, error on failure + */ +int lbs_get_tx_power(struct lbs_private *priv, s16 *curlevel, s16 *minlevel, + s16 *maxlevel) { - - struct cmd_ds_802_11_rf_tx_power *prtp = &cmd->params.txp; + struct cmd_ds_802_11_rf_tx_power cmd; + int ret; lbs_deb_enter(LBS_DEB_CMD); - cmd->size = - cpu_to_le16((sizeof(struct cmd_ds_802_11_rf_tx_power)) + S_DS_GEN); - cmd->command = cpu_to_le16(CMD_802_11_RF_TX_POWER); - prtp->action = cpu_to_le16(cmd_action); + memset(&cmd, 0, sizeof(cmd)); + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); + cmd.action = cpu_to_le16(CMD_ACT_GET); + + ret = lbs_cmd_with_response(priv, CMD_802_11_RF_TX_POWER, &cmd); + if (ret == 0) { + *curlevel = le16_to_cpu(cmd.curlevel); + if (minlevel) + *minlevel = le16_to_cpu(cmd.minlevel); + if (maxlevel) + *maxlevel = le16_to_cpu(cmd.maxlevel); + } - lbs_deb_cmd("RF_TX_POWER_CMD: size:%d cmd:0x%x Act:%d\n", - le16_to_cpu(cmd->size), le16_to_cpu(cmd->command), - le16_to_cpu(prtp->action)); + lbs_deb_leave(LBS_DEB_CMD); + return ret; +} - switch (cmd_action) { - case CMD_ACT_TX_POWER_OPT_GET: - prtp->action = cpu_to_le16(CMD_ACT_GET); - prtp->currentlevel = 0; - break; +/** + * @brief Set the TX power + * + * @param priv A pointer to struct lbs_private structure + * @param dbm The desired power level in dBm + * + * @return 0 on success, error on failure + */ +int lbs_set_tx_power(struct lbs_private *priv, s16 dbm) +{ + struct cmd_ds_802_11_rf_tx_power cmd; + int ret; - case CMD_ACT_TX_POWER_OPT_SET_HIGH: - prtp->action = cpu_to_le16(CMD_ACT_SET); - prtp->currentlevel = cpu_to_le16(CMD_ACT_TX_POWER_INDEX_HIGH); - break; + lbs_deb_enter(LBS_DEB_CMD); - case CMD_ACT_TX_POWER_OPT_SET_MID: - prtp->action = cpu_to_le16(CMD_ACT_SET); - prtp->currentlevel = cpu_to_le16(CMD_ACT_TX_POWER_INDEX_MID); - break; + memset(&cmd, 0, sizeof(cmd)); + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); + cmd.action = cpu_to_le16(CMD_ACT_SET); + cmd.curlevel = cpu_to_le16(dbm); - case CMD_ACT_TX_POWER_OPT_SET_LOW: - prtp->action = cpu_to_le16(CMD_ACT_SET); - prtp->currentlevel = cpu_to_le16(*((u16 *) pdata_buf)); - break; - } + lbs_deb_cmd("SET_RF_TX_POWER: %d dBm\n", dbm); + + ret = lbs_cmd_with_response(priv, CMD_802_11_RF_TX_POWER, &cmd); lbs_deb_leave(LBS_DEB_CMD); - return 0; + return ret; } static int lbs_cmd_802_11_monitor_mode(struct cmd_ds_command *cmd, @@ -1269,41 +1289,47 @@ void lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd, 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; + int ret = -EINVAL; lbs_deb_enter(LBS_DEB_CMD); cmd.hdr.size = cpu_to_le16(sizeof(cmd)); cmd.action = cpu_to_le16(CMD_ACT_SET); - switch (priv->preamble) { - case CMD_TYPE_SHORT_PREAMBLE: - cmd.control = cpu_to_le16(SET_SHORT_PREAMBLE); - break; - - case CMD_TYPE_LONG_PREAMBLE: - cmd.control = cpu_to_le16(SET_LONG_PREAMBLE); - break; + /* Only v8 and below support setting the preamble */ + if (priv->fwrelease < 0x09000000) { + switch (preamble) { + case RADIO_PREAMBLE_SHORT: + if (!(priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)) + goto out; + /* Fall through */ + case RADIO_PREAMBLE_AUTO: + case RADIO_PREAMBLE_LONG: + cmd.control = cpu_to_le16(preamble); + break; + default: + goto out; + } + } - case CMD_TYPE_AUTO_PREAMBLE: - default: - cmd.control = cpu_to_le16(SET_AUTO_PREAMBLE); - break; + if (radio_on) + cmd.control |= cpu_to_le16(0x1); + else { + cmd.control &= cpu_to_le16(~0x1); + priv->txpower_cur = 0; } - if (priv->radioon) - cmd.control |= cpu_to_le16(TURN_ON_RF); - else - cmd.control &= cpu_to_le16(~TURN_ON_RF); + lbs_deb_cmd("RADIO_CONTROL: radio %s, preamble %d\n", + radio_on ? "ON" : "OFF", preamble); - lbs_deb_cmd("RADIO_SET: radio %d, preamble %d\n", priv->radioon, - priv->preamble); + priv->radio_on = radio_on; ret = lbs_cmd_with_response(priv, CMD_802_11_RADIO_CONTROL, &cmd); +out: lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); return ret; } @@ -1393,14 +1419,6 @@ int lbs_prepare_and_send_command(struct lbs_private *priv, ret = lbs_cmd_80211_associate(priv, cmdptr, pdata_buf); break; - case CMD_802_11_DEAUTHENTICATE: - ret = lbs_cmd_80211_deauthenticate(priv, cmdptr); - break; - - case CMD_802_11_AD_HOC_START: - ret = lbs_cmd_80211_ad_hoc_start(priv, cmdptr, pdata_buf); - break; - case CMD_802_11_RESET: ret = lbs_cmd_802_11_reset(cmdptr, cmd_action); break; @@ -1420,28 +1438,15 @@ int lbs_prepare_and_send_command(struct lbs_private *priv, ret = lbs_cmd_reg_access(cmdptr, cmd_action, pdata_buf); break; - case CMD_802_11_RF_TX_POWER: - ret = lbs_cmd_802_11_rf_tx_power(cmdptr, - cmd_action, pdata_buf); - break; - case CMD_802_11_MONITOR_MODE: ret = lbs_cmd_802_11_monitor_mode(cmdptr, cmd_action, pdata_buf); break; - case CMD_802_11_AD_HOC_JOIN: - ret = lbs_cmd_80211_ad_hoc_join(priv, cmdptr, pdata_buf); - break; - case CMD_802_11_RSSI: ret = lbs_cmd_802_11_rssi(priv, cmdptr); break; - case CMD_802_11_AD_HOC_STOP: - ret = lbs_cmd_80211_ad_hoc_stop(cmdptr); - break; - case CMD_802_11_SET_AFC: case CMD_802_11_GET_AFC: diff --git a/drivers/net/wireless/libertas/cmd.h b/drivers/net/wireless/libertas/cmd.h index a53b51f8bdb..11ac996e895 100644 --- a/drivers/net/wireless/libertas/cmd.h +++ b/drivers/net/wireless/libertas/cmd.h @@ -61,4 +61,10 @@ int lbs_cmd_802_11_enable_rsn(struct lbs_private *priv, uint16_t cmd_action, int lbs_cmd_802_11_key_material(struct lbs_private *priv, uint16_t cmd_action, struct assoc_request *assoc); +int lbs_get_tx_power(struct lbs_private *priv, s16 *curlevel, s16 *minlevel, + s16 *maxlevel); +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 */ diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index 24de3c3cf87..0371c83f566 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -188,21 +188,6 @@ static int lbs_ret_802_11_snmp_mib(struct lbs_private *priv, return 0; } -static int lbs_ret_802_11_rf_tx_power(struct lbs_private *priv, - struct cmd_ds_command *resp) -{ - struct cmd_ds_802_11_rf_tx_power *rtp = &resp->params.txp; - - lbs_deb_enter(LBS_DEB_CMD); - - priv->txpowerlevel = le16_to_cpu(rtp->currentlevel); - - lbs_deb_cmd("TX power currently %d\n", priv->txpowerlevel); - - lbs_deb_leave(LBS_DEB_CMD); - return 0; -} - static int lbs_ret_802_11_rssi(struct lbs_private *priv, struct cmd_ds_command *resp) { @@ -273,24 +258,10 @@ static inline int handle_cmd_response(struct lbs_private *priv, ret = lbs_ret_80211_associate(priv, resp); break; - case CMD_RET(CMD_802_11_DISASSOCIATE): - case CMD_RET(CMD_802_11_DEAUTHENTICATE): - ret = lbs_ret_80211_disassociate(priv); - break; - - case CMD_RET(CMD_802_11_AD_HOC_START): - case CMD_RET(CMD_802_11_AD_HOC_JOIN): - ret = lbs_ret_80211_ad_hoc_start(priv, resp); - break; - case CMD_RET(CMD_802_11_SNMP_MIB): ret = lbs_ret_802_11_snmp_mib(priv, resp); break; - case CMD_RET(CMD_802_11_RF_TX_POWER): - ret = lbs_ret_802_11_rf_tx_power(priv, resp); - break; - case CMD_RET(CMD_802_11_SET_AFC): case CMD_RET(CMD_802_11_GET_AFC): spin_lock_irqsave(&priv->driver_lock, flags); @@ -309,10 +280,6 @@ static inline int handle_cmd_response(struct lbs_private *priv, ret = lbs_ret_802_11_rssi(priv, resp); break; - case CMD_RET(CMD_802_11_AD_HOC_STOP): - ret = lbs_ret_80211_ad_hoc_stop(priv); - break; - case CMD_RET(CMD_802_11D_DOMAIN_INFO): ret = lbs_ret_802_11d_domain_info(resp); break; diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h index a8ac974daca..1a8888ccead 100644 --- a/drivers/net/wireless/libertas/decl.h +++ b/drivers/net/wireless/libertas/decl.h @@ -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_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); u8 lbs_data_rate_to_fw_index(u32 rate); diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index f5bb40c54d8..fd59e181646 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -253,7 +253,9 @@ struct lbs_private { u32 connect_status; u32 mesh_connect_status; u16 regioncode; - u16 txpowerlevel; + s16 txpower_cur; + s16 txpower_min; + s16 txpower_max; /** POWER MANAGEMENT AND PnP SUPPORT */ u8 surpriseremoved; @@ -291,8 +293,7 @@ struct lbs_private { u16 nextSNRNF; u16 numSNRNF; - u8 radioon; - u32 preamble; + u8 radio_on; /** data rate stuff */ u8 cur_rate; diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h index c92e41b4faf..da618fc997c 100644 --- a/drivers/net/wireless/libertas/host.h +++ b/drivers/net/wireless/libertas/host.h @@ -61,7 +61,6 @@ #define CMD_RF_REG_MAP 0x0023 #define CMD_802_11_DEAUTHENTICATE 0x0024 #define CMD_802_11_REASSOCIATE 0x0025 -#define CMD_802_11_DISASSOCIATE 0x0026 #define CMD_MAC_CONTROL 0x0028 #define CMD_802_11_AD_HOC_START 0x002b #define CMD_802_11_AD_HOC_JOIN 0x002c @@ -153,11 +152,6 @@ #define CMD_ACT_MAC_ALL_MULTICAST_ENABLE 0x0100 #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 */ #define CMD_SUBSCRIBE_RSSI_LOW 0x0001 #define CMD_SUBSCRIBE_SNR_LOW 0x0002 @@ -166,28 +160,14 @@ #define CMD_SUBSCRIBE_RSSI_HIGH 0x0010 #define CMD_SUBSCRIBE_SNR_HIGH 0x0020 -#define TURN_ON_RF 0x01 -#define RADIO_ON 0x01 -#define RADIO_OFF 0x00 - -#define SET_AUTO_PREAMBLE 0x05 -#define SET_SHORT_PREAMBLE 0x03 -#define SET_LONG_PREAMBLE 0x01 +#define RADIO_PREAMBLE_LONG 0x00 +#define RADIO_PREAMBLE_SHORT 0x02 +#define RADIO_PREAMBLE_AUTO 0x04 /* 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_SET 0x01 -/* Define action or option for CMD_802_11_RF_TX_POWER */ -#define CMD_ACT_TX_POWER_OPT_GET 0x0000 -#define CMD_ACT_TX_POWER_OPT_SET_HIGH 0x8007 -#define CMD_ACT_TX_POWER_OPT_SET_MID 0x8004 -#define CMD_ACT_TX_POWER_OPT_SET_LOW 0x8000 - -#define CMD_ACT_TX_POWER_INDEX_HIGH 0x0007 -#define CMD_ACT_TX_POWER_INDEX_MID 0x0004 -#define CMD_ACT_TX_POWER_INDEX_LOW 0x0000 - /* Define action or option for CMD_802_11_DATA_RATE */ #define CMD_ACT_SET_TX_AUTO 0x0000 #define CMD_ACT_SET_TX_FIX_RATE 0x0001 diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h index 913b480211a..d27c276b219 100644 --- a/drivers/net/wireless/libertas/hostcmd.h +++ b/drivers/net/wireless/libertas/hostcmd.h @@ -232,7 +232,9 @@ struct cmd_ds_802_11_authenticate { }; struct cmd_ds_802_11_deauthenticate { - u8 macaddr[6]; + struct cmd_header hdr; + + u8 macaddr[ETH_ALEN]; __le16 reasoncode; }; @@ -251,20 +253,10 @@ struct cmd_ds_802_11_associate { #endif } __attribute__ ((packed)); -struct cmd_ds_802_11_disassociate { - u8 destmacaddr[6]; - __le16 reasoncode; -}; - struct cmd_ds_802_11_associate_rsp { struct ieeetypes_assocrsp assocRsp; }; -struct cmd_ds_802_11_ad_hoc_result { - u8 pad[3]; - u8 bssid[ETH_ALEN]; -}; - struct cmd_ds_802_11_set_wep { struct cmd_header hdr; @@ -435,8 +427,12 @@ struct cmd_ds_802_11_mac_address { }; struct cmd_ds_802_11_rf_tx_power { + struct cmd_header hdr; + __le16 action; - __le16 currentlevel; + __le16 curlevel; + s8 maxlevel; + s8 minlevel; }; struct cmd_ds_802_11_rf_antenna { @@ -507,10 +503,12 @@ struct cmd_ds_802_11_rate_adapt_rateset { }; struct cmd_ds_802_11_ad_hoc_start { + struct cmd_header hdr; + u8 ssid[IW_ESSID_MAX_SIZE]; u8 bsstype; __le16 beaconperiod; - u8 dtimperiod; + u8 dtimperiod; /* Reserved on v9 and later */ union IEEEtypes_ssparamset ssparamset; union ieeetypes_phyparamset phyparamset; __le16 probedelay; @@ -519,9 +517,16 @@ struct cmd_ds_802_11_ad_hoc_start { u8 tlv_memory_size_pad[100]; } __attribute__ ((packed)); +struct cmd_ds_802_11_ad_hoc_result { + struct cmd_header hdr; + + u8 pad[3]; + u8 bssid[ETH_ALEN]; +}; + struct adhoc_bssdesc { - u8 bssid[6]; - u8 ssid[32]; + u8 bssid[ETH_ALEN]; + u8 ssid[IW_ESSID_MAX_SIZE]; u8 type; __le16 beaconperiod; u8 dtimperiod; @@ -539,10 +544,15 @@ struct adhoc_bssdesc { } __attribute__ ((packed)); struct cmd_ds_802_11_ad_hoc_join { + struct cmd_header hdr; + struct adhoc_bssdesc bss; - __le16 failtimeout; - __le16 probedelay; + __le16 failtimeout; /* Reserved on v9 and later */ + __le16 probedelay; /* Reserved on v9 and later */ +} __attribute__ ((packed)); +struct cmd_ds_802_11_ad_hoc_stop { + struct cmd_header hdr; } __attribute__ ((packed)); struct cmd_ds_802_11_enable_rsn { @@ -693,21 +703,15 @@ struct cmd_ds_command { union { struct cmd_ds_802_11_ps_mode psmode; struct cmd_ds_802_11_associate associate; - struct cmd_ds_802_11_deauthenticate deauth; - struct cmd_ds_802_11_ad_hoc_start ads; struct cmd_ds_802_11_reset reset; - struct cmd_ds_802_11_ad_hoc_result result; struct cmd_ds_802_11_authenticate auth; struct cmd_ds_802_11_get_stat gstat; struct cmd_ds_802_3_get_stat gstat_8023; struct cmd_ds_802_11_snmp_mib smib; - struct cmd_ds_802_11_rf_tx_power txp; struct cmd_ds_802_11_rf_antenna rant; struct cmd_ds_802_11_monitor_mode monitor; - struct cmd_ds_802_11_ad_hoc_join adj; struct cmd_ds_802_11_rssi rssi; struct cmd_ds_802_11_rssi_rsp rssirsp; - struct cmd_ds_802_11_disassociate dassociate; struct cmd_ds_mac_reg_access macreg; struct cmd_ds_bbp_reg_access bbpreg; struct cmd_ds_rf_reg_access rfreg; diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index bd32ac0b4e0..2436634b6b7 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -291,9 +291,11 @@ static ssize_t lbs_rtap_set(struct device *dev, if (priv->infra_open || priv->mesh_open) return -EBUSY; if (priv->mode == IW_MODE_INFRA) - lbs_send_deauthentication(priv); + lbs_cmd_80211_deauthenticate(priv, + priv->curbssparams.bssid, + WLAN_REASON_DEAUTH_LEAVING); else if (priv->mode == IW_MODE_ADHOC) - lbs_stop_adhoc_network(priv); + lbs_adhoc_stop(priv); lbs_add_rtap(priv); } priv->monitormode = monitor_mode; @@ -956,17 +958,24 @@ EXPORT_SYMBOL_GPL(lbs_resume); static int lbs_setup_firmware(struct lbs_private *priv) { int ret = -1; + s16 curlevel = 0, minlevel = 0, maxlevel = 0; lbs_deb_enter(LBS_DEB_FW); - /* - * Read MAC address from HW - */ + /* Read MAC address from firmware */ memset(priv->current_addr, 0xff, ETH_ALEN); ret = lbs_update_hw_spec(priv); if (ret) goto done; + /* Read power levels if available */ + ret = lbs_get_tx_power(priv, &curlevel, &minlevel, &maxlevel); + if (ret == 0) { + priv->txpower_cur = curlevel; + priv->txpower_min = minlevel; + priv->txpower_max = maxlevel; + } + lbs_set_mac_control(priv); done: lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret); @@ -1042,7 +1051,7 @@ static int lbs_init_adapter(struct lbs_private *priv) priv->mode = IW_MODE_INFRA; priv->curbssparams.channel = DEFAULT_AD_HOC_CHANNEL; 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->capability = WLAN_CAPABILITY_SHORT_PREAMBLE; priv->psmode = LBS802_11POWERMODECAM; diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index 4b274562f96..8f66903641b 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -944,6 +944,11 @@ int lbs_set_scan(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_WEXT); + if (!priv->radio_on) { + ret = -EINVAL; + goto out; + } + if (!netif_running(dev)) { ret = -ENETDOWN; goto out; diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index 8b3ed77860b..426f1fe3bb4 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -120,34 +120,6 @@ static struct chan_freq_power *find_cfp_by_band_and_freq( 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 * @@ -420,28 +392,30 @@ static int lbs_get_txpow(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { - int ret = 0; struct lbs_private *priv = dev->priv; + s16 curlevel = 0; + int ret = 0; lbs_deb_enter(LBS_DEB_WEXT); - ret = lbs_prepare_and_send_command(priv, - CMD_802_11_RF_TX_POWER, - CMD_ACT_TX_POWER_OPT_GET, - CMD_OPTION_WAITFORRSP, 0, NULL); + 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); if (ret) goto out; - lbs_deb_wext("tx power level %d dbm\n", priv->txpowerlevel); - vwrq->value = priv->txpowerlevel; + lbs_deb_wext("tx power level %d dbm\n", curlevel); + priv->txpower_cur = curlevel; + + vwrq->value = curlevel; vwrq->fixed = 1; - if (priv->radioon) { - vwrq->disabled = 0; - vwrq->flags = IW_TXPOW_DBM; - } else { - vwrq->disabled = 1; - } + vwrq->disabled = 0; + vwrq->flags = IW_TXPOW_DBM; out: lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); @@ -693,22 +667,12 @@ static int lbs_get_range(struct net_device *dev, struct iw_request_info *info, range->sensitivity = 0; - /* - * Setup the supported power level ranges - */ + /* Setup the supported power level ranges */ memset(range->txpower, 0, sizeof(range->txpower)); - range->txpower[0] = 5; - range->txpower[1] = 7; - range->txpower[2] = 9; - range->txpower[3] = 11; - range->txpower[4] = 13; - range->txpower[5] = 15; - range->txpower[6] = 17; - range->txpower[7] = 19; - - range->num_txpower = 8; - range->txpower_capa = IW_TXPOW_DBM; - range->txpower_capa |= IW_TXPOW_RANGE; + range->txpower_capa = IW_TXPOW_DBM | IW_TXPOW_RANGE; + range->txpower[0] = priv->txpower_min; + range->txpower[1] = priv->txpower_max; + range->num_txpower = 2; range->event_capa[0] = (IW_EVENT_CAPA_K_0 | IW_EVENT_CAPA_MASK(SIOCGIWAP) | @@ -998,9 +962,11 @@ static int lbs_mesh_set_freq(struct net_device *dev, if (fwrq->m != priv->curbssparams.channel) { lbs_deb_wext("mesh channel change forces eth disconnect\n"); if (priv->mode == IW_MODE_INFRA) - lbs_send_deauthentication(priv); + lbs_cmd_80211_deauthenticate(priv, + priv->curbssparams.bssid, + WLAN_REASON_DEAUTH_LEAVING); else if (priv->mode == IW_MODE_ADHOC) - lbs_stop_adhoc_network(priv); + lbs_adhoc_stop(priv); } lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, fwrq->m); lbs_update_channel(priv); @@ -1844,39 +1810,50 @@ static int lbs_set_txpow(struct net_device *dev, struct iw_request_info *info, { int ret = 0; struct lbs_private *priv = dev->priv; - - u16 dbm; + s16 dbm = (s16) vwrq->value; lbs_deb_enter(LBS_DEB_WEXT); if (vwrq->disabled) { - lbs_radio_ioctl(priv, RADIO_OFF); - return 0; + lbs_set_radio(priv, RADIO_PREAMBLE_AUTO, 0); + goto out; } - priv->preamble = CMD_TYPE_AUTO_PREAMBLE; - - lbs_radio_ioctl(priv, RADIO_ON); + if (vwrq->fixed == 0) { + /* Auto power control */ + dbm = priv->txpower_max; + } else { + /* Userspace check in iwrange if it should use dBm or mW, + * therefore this should never happen... Jean II */ + if ((vwrq->flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) { + ret = -EOPNOTSUPP; + goto out; + } - /* Userspace check in iwrange if it should use dBm or mW, - * therefore this should never happen... Jean II */ - if ((vwrq->flags & IW_TXPOW_TYPE) == IW_TXPOW_MWATT) { - return -EOPNOTSUPP; - } else - dbm = (u16) vwrq->value; + /* Validate requested power level against firmware allowed levels */ + if (priv->txpower_min && (dbm < priv->txpower_min)) { + ret = -EINVAL; + goto out; + } - /* auto tx power control */ + if (priv->txpower_max && (dbm > priv->txpower_max)) { + ret = -EINVAL; + goto out; + } + } - if (vwrq->fixed == 0) - dbm = 0xffff; + /* 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); - ret = lbs_prepare_and_send_command(priv, - CMD_802_11_RF_TX_POWER, - CMD_ACT_TX_POWER_OPT_SET_LOW, - CMD_OPTION_WAITFORRSP, 0, (void *)&dbm); + ret = lbs_set_tx_power(priv, dbm); +out: lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); return ret; } @@ -1928,6 +1905,11 @@ static int lbs_set_essid(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_WEXT); + if (!priv->radio_on) { + ret = -EINVAL; + goto out; + } + /* Check the size of the string */ if (in_ssid_len > IW_ESSID_MAX_SIZE) { ret = -E2BIG; @@ -2005,6 +1987,11 @@ static int lbs_mesh_set_essid(struct net_device *dev, lbs_deb_enter(LBS_DEB_WEXT); + if (!priv->radio_on) { + ret = -EINVAL; + goto out; + } + /* Check the size of the string */ if (dwrq->length > IW_ESSID_MAX_SIZE) { ret = -E2BIG; @@ -2046,6 +2033,9 @@ static int lbs_set_wap(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_WEXT); + if (!priv->radio_on) + return -EINVAL; + if (awrq->sa_family != ARPHRD_ETHER) return -EINVAL; |