diff options
Diffstat (limited to 'drivers/net/wireless/wl12xx/scan.c')
-rw-r--r-- | drivers/net/wireless/wl12xx/scan.c | 122 |
1 files changed, 74 insertions, 48 deletions
diff --git a/drivers/net/wireless/wl12xx/scan.c b/drivers/net/wireless/wl12xx/scan.c index 128ccb79318..e24111ececc 100644 --- a/drivers/net/wireless/wl12xx/scan.c +++ b/drivers/net/wireless/wl12xx/scan.c @@ -24,6 +24,7 @@ #include <linux/ieee80211.h> #include "wl12xx.h" +#include "debug.h" #include "cmd.h" #include "scan.h" #include "acx.h" @@ -34,6 +35,8 @@ void wl1271_scan_complete_work(struct work_struct *work) { struct delayed_work *dwork; struct wl1271 *wl; + struct ieee80211_vif *vif; + struct wl12xx_vif *wlvif; int ret; bool is_sta, is_ibss; @@ -50,28 +53,31 @@ void wl1271_scan_complete_work(struct work_struct *work) if (wl->scan.state == WL1271_SCAN_STATE_IDLE) goto out; + vif = wl->scan_vif; + wlvif = wl12xx_vif_to_data(vif); + wl->scan.state = WL1271_SCAN_STATE_IDLE; memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch)); wl->scan.req = NULL; + wl->scan_vif = NULL; ret = wl1271_ps_elp_wakeup(wl); if (ret < 0) goto out; - if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) { + if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) { /* restore hardware connection monitoring template */ - wl1271_cmd_build_ap_probe_req(wl, wl->probereq); + wl1271_cmd_build_ap_probe_req(wl, wlvif, wlvif->probereq); } /* return to ROC if needed */ - is_sta = (wl->bss_type == BSS_TYPE_STA_BSS); - is_ibss = (wl->bss_type == BSS_TYPE_IBSS); - if (((is_sta && !test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) || - (is_ibss && !test_bit(WL1271_FLAG_IBSS_JOINED, &wl->flags))) && - !test_bit(wl->dev_role_id, wl->roc_map)) { + is_sta = (wlvif->bss_type == BSS_TYPE_STA_BSS); + is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS); + if (((is_sta && !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) || + (is_ibss && !test_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags))) && + !test_bit(wlvif->dev_role_id, wl->roc_map)) { /* restore remain on channel */ - wl12xx_cmd_role_start_dev(wl); - wl12xx_roc(wl, wl->dev_role_id); + wl12xx_start_dev(wl, wlvif); } wl1271_ps_elp_sleep(wl); @@ -155,9 +161,11 @@ static int wl1271_get_scan_channels(struct wl1271 *wl, #define WL1271_NOTHING_TO_SCAN 1 -static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band, - bool passive, u32 basic_rate) +static int wl1271_scan_send(struct wl1271 *wl, struct ieee80211_vif *vif, + enum ieee80211_band band, + bool passive, u32 basic_rate) { + struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); struct wl1271_cmd_scan *cmd; struct wl1271_cmd_trigger_scan_to *trigger; int ret; @@ -177,11 +185,11 @@ static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band, if (passive) scan_options |= WL1271_SCAN_OPT_PASSIVE; - if (WARN_ON(wl->role_id == WL12XX_INVALID_ROLE_ID)) { + if (WARN_ON(wlvif->role_id == WL12XX_INVALID_ROLE_ID)) { ret = -EINVAL; goto out; } - cmd->params.role_id = wl->role_id; + cmd->params.role_id = wlvif->role_id; cmd->params.scan_options = cpu_to_le16(scan_options); cmd->params.n_ch = wl1271_get_scan_channels(wl, wl->scan.req, @@ -194,7 +202,6 @@ static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band, cmd->params.tx_rate = cpu_to_le32(basic_rate); cmd->params.n_probe_reqs = wl->conf.scan.num_probe_reqs; - cmd->params.tx_rate = cpu_to_le32(basic_rate); cmd->params.tid_trigger = 0; cmd->params.scan_tag = WL1271_SCAN_DEFAULT_TAG; @@ -208,11 +215,11 @@ static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band, memcpy(cmd->params.ssid, wl->scan.ssid, wl->scan.ssid_len); } - memcpy(cmd->addr, wl->mac_addr, ETH_ALEN); + memcpy(cmd->addr, vif->addr, ETH_ALEN); - ret = wl1271_cmd_build_probe_req(wl, wl->scan.ssid, wl->scan.ssid_len, - wl->scan.req->ie, wl->scan.req->ie_len, - band); + ret = wl1271_cmd_build_probe_req(wl, wlvif, wl->scan.ssid, + wl->scan.ssid_len, wl->scan.req->ie, + wl->scan.req->ie_len, band); if (ret < 0) { wl1271_error("PROBE request template failed"); goto out; @@ -241,11 +248,12 @@ out: return ret; } -void wl1271_scan_stm(struct wl1271 *wl) +void wl1271_scan_stm(struct wl1271 *wl, struct ieee80211_vif *vif) { + struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); int ret = 0; enum ieee80211_band band; - u32 rate; + u32 rate, mask; switch (wl->scan.state) { case WL1271_SCAN_STATE_IDLE: @@ -253,47 +261,59 @@ void wl1271_scan_stm(struct wl1271 *wl) case WL1271_SCAN_STATE_2GHZ_ACTIVE: band = IEEE80211_BAND_2GHZ; - rate = wl1271_tx_min_rate_get(wl, wl->bitrate_masks[band]); - ret = wl1271_scan_send(wl, band, false, rate); + mask = wlvif->bitrate_masks[band]; + if (wl->scan.req->no_cck) { + mask &= ~CONF_TX_CCK_RATES; + if (!mask) + mask = CONF_TX_RATE_MASK_BASIC_P2P; + } + rate = wl1271_tx_min_rate_get(wl, mask); + ret = wl1271_scan_send(wl, vif, band, false, rate); if (ret == WL1271_NOTHING_TO_SCAN) { wl->scan.state = WL1271_SCAN_STATE_2GHZ_PASSIVE; - wl1271_scan_stm(wl); + wl1271_scan_stm(wl, vif); } break; case WL1271_SCAN_STATE_2GHZ_PASSIVE: band = IEEE80211_BAND_2GHZ; - rate = wl1271_tx_min_rate_get(wl, wl->bitrate_masks[band]); - ret = wl1271_scan_send(wl, band, true, rate); + mask = wlvif->bitrate_masks[band]; + if (wl->scan.req->no_cck) { + mask &= ~CONF_TX_CCK_RATES; + if (!mask) + mask = CONF_TX_RATE_MASK_BASIC_P2P; + } + rate = wl1271_tx_min_rate_get(wl, mask); + ret = wl1271_scan_send(wl, vif, band, true, rate); if (ret == WL1271_NOTHING_TO_SCAN) { if (wl->enable_11a) wl->scan.state = WL1271_SCAN_STATE_5GHZ_ACTIVE; else wl->scan.state = WL1271_SCAN_STATE_DONE; - wl1271_scan_stm(wl); + wl1271_scan_stm(wl, vif); } break; case WL1271_SCAN_STATE_5GHZ_ACTIVE: band = IEEE80211_BAND_5GHZ; - rate = wl1271_tx_min_rate_get(wl, wl->bitrate_masks[band]); - ret = wl1271_scan_send(wl, band, false, rate); + rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[band]); + ret = wl1271_scan_send(wl, vif, band, false, rate); if (ret == WL1271_NOTHING_TO_SCAN) { wl->scan.state = WL1271_SCAN_STATE_5GHZ_PASSIVE; - wl1271_scan_stm(wl); + wl1271_scan_stm(wl, vif); } break; case WL1271_SCAN_STATE_5GHZ_PASSIVE: band = IEEE80211_BAND_5GHZ; - rate = wl1271_tx_min_rate_get(wl, wl->bitrate_masks[band]); - ret = wl1271_scan_send(wl, band, true, rate); + rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[band]); + ret = wl1271_scan_send(wl, vif, band, true, rate); if (ret == WL1271_NOTHING_TO_SCAN) { wl->scan.state = WL1271_SCAN_STATE_DONE; - wl1271_scan_stm(wl); + wl1271_scan_stm(wl, vif); } break; @@ -317,7 +337,8 @@ void wl1271_scan_stm(struct wl1271 *wl) } } -int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len, +int wl1271_scan(struct wl1271 *wl, struct ieee80211_vif *vif, + const u8 *ssid, size_t ssid_len, struct cfg80211_scan_request *req) { /* @@ -338,6 +359,7 @@ int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len, wl->scan.ssid_len = 0; } + wl->scan_vif = vif; wl->scan.req = req; memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch)); @@ -346,7 +368,7 @@ int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len, ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work, msecs_to_jiffies(WL1271_SCAN_TIMEOUT)); - wl1271_scan_stm(wl); + wl1271_scan_stm(wl, vif); return 0; } @@ -415,18 +437,19 @@ wl1271_scan_get_sched_scan_channels(struct wl1271 *wl, if (flags & IEEE80211_CHAN_RADAR) { channels[j].flags |= SCAN_CHANNEL_FLAGS_DFS; + channels[j].passive_duration = cpu_to_le16(c->dwell_time_dfs); - } - else if (flags & IEEE80211_CHAN_PASSIVE_SCAN) { + } else { channels[j].passive_duration = cpu_to_le16(c->dwell_time_passive); - } else { - channels[j].min_duration = - cpu_to_le16(c->min_dwell_time_active); - channels[j].max_duration = - cpu_to_le16(c->max_dwell_time_active); } + + channels[j].min_duration = + cpu_to_le16(c->min_dwell_time_active); + channels[j].max_duration = + cpu_to_le16(c->max_dwell_time_active); + channels[j].tx_power_att = req->channels[i]->max_power; channels[j].channel = req->channels[i]->hw_value; @@ -550,6 +573,9 @@ wl12xx_scan_sched_scan_ssid_list(struct wl1271 *wl, * so they're used in probe requests. */ for (i = 0; i < req->n_ssids; i++) { + if (!req->ssids[i].ssid_len) + continue; + for (j = 0; j < cmd->n_ssids; j++) if (!memcmp(req->ssids[i].ssid, cmd->ssids[j].ssid, @@ -559,7 +585,7 @@ wl12xx_scan_sched_scan_ssid_list(struct wl1271 *wl, break; } /* Fail if SSID isn't present in the filters */ - if (j == req->n_ssids) { + if (j == cmd->n_ssids) { ret = -EINVAL; goto out_free; } @@ -585,6 +611,7 @@ out: } int wl1271_scan_sched_scan_config(struct wl1271 *wl, + struct wl12xx_vif *wlvif, struct cfg80211_sched_scan_request *req, struct ieee80211_sched_scan_ies *ies) { @@ -631,7 +658,7 @@ int wl1271_scan_sched_scan_config(struct wl1271 *wl, } if (!force_passive && cfg->active[0]) { - ret = wl1271_cmd_build_probe_req(wl, req->ssids[0].ssid, + ret = wl1271_cmd_build_probe_req(wl, wlvif, req->ssids[0].ssid, req->ssids[0].ssid_len, ies->ie[IEEE80211_BAND_2GHZ], ies->len[IEEE80211_BAND_2GHZ], @@ -643,7 +670,7 @@ int wl1271_scan_sched_scan_config(struct wl1271 *wl, } if (!force_passive && cfg->active[1]) { - ret = wl1271_cmd_build_probe_req(wl, req->ssids[0].ssid, + ret = wl1271_cmd_build_probe_req(wl, wlvif, req->ssids[0].ssid, req->ssids[0].ssid_len, ies->ie[IEEE80211_BAND_5GHZ], ies->len[IEEE80211_BAND_5GHZ], @@ -667,17 +694,17 @@ out: return ret; } -int wl1271_scan_sched_scan_start(struct wl1271 *wl) +int wl1271_scan_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif) { struct wl1271_cmd_sched_scan_start *start; int ret = 0; wl1271_debug(DEBUG_CMD, "cmd periodic scan start"); - if (wl->bss_type != BSS_TYPE_STA_BSS) + if (wlvif->bss_type != BSS_TYPE_STA_BSS) return -EOPNOTSUPP; - if (!test_bit(WL1271_FLAG_IDLE, &wl->flags)) + if (test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags)) return -EBUSY; start = kzalloc(sizeof(*start), GFP_KERNEL); @@ -727,7 +754,6 @@ void wl1271_scan_sched_scan_stop(struct wl1271 *wl) wl1271_error("failed to send sched scan stop command"); goto out_free; } - wl->sched_scanning = false; out_free: kfree(stop); |