1/* 2 * This file is part of wl1271 3 * 4 * Copyright (C) 2009-2010 Nokia Corporation 5 * 6 * Contact: Luciano Coelho <luciano.coelho@nokia.com> 7 * 8 * This program is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU General Public License 10 * version 2 as published by the Free Software Foundation. 11 * 12 * This program is distributed in the hope that it will be useful, but 13 * WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 * 02110-1301 USA 21 * 22 */ 23 24#include <linux/ieee80211.h> 25 26#include "wl1271.h" 27#include "wl1271_cmd.h" 28#include "wl1271_scan.h" 29#include "wl1271_acx.h" 30 31static int wl1271_get_scan_channels(struct wl1271 *wl, 32 struct cfg80211_scan_request *req, 33 struct basic_scan_channel_params *channels, 34 enum ieee80211_band band, bool passive) 35{ 36 int i, j; 37 u32 flags; 38 39 for (i = 0, j = 0; 40 i < req->n_channels && j < WL1271_SCAN_MAX_CHANNELS; 41 i++) { 42 43 flags = req->channels[i]->flags; 44 45 if (!wl->scan.scanned_ch[i] && 46 !(flags & IEEE80211_CHAN_DISABLED) && 47 ((!!(flags & IEEE80211_CHAN_PASSIVE_SCAN)) == passive) && 48 (req->channels[i]->band == band)) { 49 50 wl1271_debug(DEBUG_SCAN, "band %d, center_freq %d ", 51 req->channels[i]->band, 52 req->channels[i]->center_freq); 53 wl1271_debug(DEBUG_SCAN, "hw_value %d, flags %X", 54 req->channels[i]->hw_value, 55 req->channels[i]->flags); 56 wl1271_debug(DEBUG_SCAN, 57 "max_antenna_gain %d, max_power %d", 58 req->channels[i]->max_antenna_gain, 59 req->channels[i]->max_power); 60 wl1271_debug(DEBUG_SCAN, "beacon_found %d", 61 req->channels[i]->beacon_found); 62 63 channels[j].min_duration = 64 cpu_to_le32(WL1271_SCAN_CHAN_MIN_DURATION); 65 channels[j].max_duration = 66 cpu_to_le32(WL1271_SCAN_CHAN_MAX_DURATION); 67 channels[j].early_termination = 0; 68 channels[j].tx_power_att = req->channels[i]->max_power; 69 channels[j].channel = req->channels[i]->hw_value; 70 71 memset(&channels[j].bssid_lsb, 0xff, 4); 72 memset(&channels[j].bssid_msb, 0xff, 2); 73 74 /* Mark the channels we already used */ 75 wl->scan.scanned_ch[i] = true; 76 77 j++; 78 } 79 } 80 81 return j; 82} 83 84#define WL1271_NOTHING_TO_SCAN 1 85 86static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band, 87 bool passive, u32 basic_rate) 88{ 89 struct wl1271_cmd_scan *cmd; 90 struct wl1271_cmd_trigger_scan_to *trigger; 91 int ret; 92 u16 scan_options = 0; 93 94 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 95 trigger = kzalloc(sizeof(*trigger), GFP_KERNEL); 96 if (!cmd || !trigger) { 97 ret = -ENOMEM; 98 goto out; 99 } 100 101 /* We always use high priority scans */ 102 scan_options = WL1271_SCAN_OPT_PRIORITY_HIGH; 103 if(passive) 104 scan_options |= WL1271_SCAN_OPT_PASSIVE; 105 cmd->params.scan_options = cpu_to_le16(scan_options); 106 107 cmd->params.n_ch = wl1271_get_scan_channels(wl, wl->scan.req, 108 cmd->channels, 109 band, passive); 110 if (cmd->params.n_ch == 0) { 111 ret = WL1271_NOTHING_TO_SCAN; 112 goto out; 113 } 114 115 cmd->params.tx_rate = cpu_to_le32(basic_rate); 116 cmd->params.rx_config_options = cpu_to_le32(CFG_RX_ALL_GOOD); 117 cmd->params.rx_filter_options = 118 cpu_to_le32(CFG_RX_PRSP_EN | CFG_RX_MGMT_EN | CFG_RX_BCN_EN); 119 120 cmd->params.n_probe_reqs = WL1271_SCAN_PROBE_REQS; 121 cmd->params.tx_rate = cpu_to_le32(basic_rate); 122 cmd->params.tid_trigger = 0; 123 cmd->params.scan_tag = WL1271_SCAN_DEFAULT_TAG; 124 125 if (band == IEEE80211_BAND_2GHZ) 126 cmd->params.band = WL1271_SCAN_BAND_2_4_GHZ; 127 else 128 cmd->params.band = WL1271_SCAN_BAND_5_GHZ; 129 130 if (wl->scan.ssid_len && wl->scan.ssid) { 131 cmd->params.ssid_len = wl->scan.ssid_len; 132 memcpy(cmd->params.ssid, wl->scan.ssid, wl->scan.ssid_len); 133 } 134 135 ret = wl1271_cmd_build_probe_req(wl, wl->scan.ssid, wl->scan.ssid_len, 136 wl->scan.req->ie, wl->scan.req->ie_len, 137 band); 138 if (ret < 0) { 139 wl1271_error("PROBE request template failed"); 140 goto out; 141 } 142 143 /* disable the timeout */ 144 trigger->timeout = 0; 145 ret = wl1271_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger, 146 sizeof(*trigger), 0); 147 if (ret < 0) { 148 wl1271_error("trigger scan to failed for hw scan"); 149 goto out; 150 } 151 152 wl1271_dump(DEBUG_SCAN, "SCAN: ", cmd, sizeof(*cmd)); 153 154 ret = wl1271_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd), 0); 155 if (ret < 0) { 156 wl1271_error("SCAN failed"); 157 goto out; 158 } 159 160out: 161 kfree(cmd); 162 kfree(trigger); 163 return ret; 164} 165 166void wl1271_scan_stm(struct wl1271 *wl) 167{ 168 int ret; 169 170 switch (wl->scan.state) { 171 case WL1271_SCAN_STATE_IDLE: 172 break; 173 174 case WL1271_SCAN_STATE_2GHZ_ACTIVE: 175 ret = wl1271_scan_send(wl, IEEE80211_BAND_2GHZ, false, 176 wl->conf.tx.basic_rate); 177 if (ret == WL1271_NOTHING_TO_SCAN) { 178 wl->scan.state = WL1271_SCAN_STATE_2GHZ_PASSIVE; 179 wl1271_scan_stm(wl); 180 } 181 182 break; 183 184 case WL1271_SCAN_STATE_2GHZ_PASSIVE: 185 ret = wl1271_scan_send(wl, IEEE80211_BAND_2GHZ, true, 186 wl->conf.tx.basic_rate); 187 if (ret == WL1271_NOTHING_TO_SCAN) { 188 if (wl1271_11a_enabled()) 189 wl->scan.state = WL1271_SCAN_STATE_5GHZ_ACTIVE; 190 else 191 wl->scan.state = WL1271_SCAN_STATE_DONE; 192 wl1271_scan_stm(wl); 193 } 194 195 break; 196 197 case WL1271_SCAN_STATE_5GHZ_ACTIVE: 198 ret = wl1271_scan_send(wl, IEEE80211_BAND_5GHZ, false, 199 wl->conf.tx.basic_rate_5); 200 if (ret == WL1271_NOTHING_TO_SCAN) { 201 wl->scan.state = WL1271_SCAN_STATE_5GHZ_PASSIVE; 202 wl1271_scan_stm(wl); 203 } 204 205 break; 206 207 case WL1271_SCAN_STATE_5GHZ_PASSIVE: 208 ret = wl1271_scan_send(wl, IEEE80211_BAND_5GHZ, true, 209 wl->conf.tx.basic_rate_5); 210 if (ret == WL1271_NOTHING_TO_SCAN) { 211 wl->scan.state = WL1271_SCAN_STATE_DONE; 212 wl1271_scan_stm(wl); 213 } 214 215 break; 216 217 case WL1271_SCAN_STATE_DONE: 218 mutex_unlock(&wl->mutex); 219 ieee80211_scan_completed(wl->hw, false); 220 mutex_lock(&wl->mutex); 221 222 kfree(wl->scan.scanned_ch); 223 wl->scan.scanned_ch = NULL; 224 225 wl->scan.state = WL1271_SCAN_STATE_IDLE; 226 break; 227 228 default: 229 wl1271_error("invalid scan state"); 230 break; 231 } 232} 233 234int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len, 235 struct cfg80211_scan_request *req) 236{ 237 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) 238 return -EBUSY; 239 240 wl->scan.state = WL1271_SCAN_STATE_2GHZ_ACTIVE; 241 242 if (ssid_len && ssid) { 243 wl->scan.ssid_len = ssid_len; 244 memcpy(wl->scan.ssid, ssid, ssid_len); 245 } else { 246 wl->scan.ssid_len = 0; 247 } 248 249 wl->scan.req = req; 250 251 wl->scan.scanned_ch = kzalloc(req->n_channels * 252 sizeof(*wl->scan.scanned_ch), 253 GFP_KERNEL); 254 wl1271_scan_stm(wl); 255 256 return 0; 257} 258