diff options
Diffstat (limited to 'drivers/net/wireless/wl12xx/wl1271_scan.c')
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1271_scan.c | 296 |
1 files changed, 181 insertions, 115 deletions
diff --git a/drivers/net/wireless/wl12xx/wl1271_scan.c b/drivers/net/wireless/wl12xx/wl1271_scan.c index eb9b4ece4ec3..f938b33912f5 100644 --- a/drivers/net/wireless/wl12xx/wl1271_scan.c +++ b/drivers/net/wireless/wl12xx/wl1271_scan.c | |||
@@ -28,103 +28,120 @@ | |||
28 | #include "wl1271_scan.h" | 28 | #include "wl1271_scan.h" |
29 | #include "wl1271_acx.h" | 29 | #include "wl1271_acx.h" |
30 | 30 | ||
31 | int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len, | 31 | static int wl1271_get_scan_channels(struct wl1271 *wl, |
32 | struct cfg80211_scan_request *req, u8 active_scan, | 32 | struct cfg80211_scan_request *req, |
33 | u8 high_prio, u8 band, u8 probe_requests) | 33 | struct basic_scan_channel_params *channels, |
34 | enum ieee80211_band band, bool passive) | ||
34 | { | 35 | { |
36 | int i, j; | ||
37 | u32 flags; | ||
35 | 38 | ||
36 | struct wl1271_cmd_trigger_scan_to *trigger = NULL; | 39 | for (i = 0, j = 0; |
37 | struct wl1271_cmd_scan *params = NULL; | 40 | i < req->n_channels && j < WL1271_SCAN_MAX_CHANNELS; |
38 | struct ieee80211_channel *channels; | 41 | i++) { |
39 | u32 rate; | ||
40 | int i, j, n_ch, ret; | ||
41 | u16 scan_options = 0; | ||
42 | u8 ieee_band; | ||
43 | |||
44 | if (band == WL1271_SCAN_BAND_2_4_GHZ) { | ||
45 | ieee_band = IEEE80211_BAND_2GHZ; | ||
46 | rate = wl->conf.tx.basic_rate; | ||
47 | } else if (band == WL1271_SCAN_BAND_DUAL && wl1271_11a_enabled()) { | ||
48 | ieee_band = IEEE80211_BAND_2GHZ; | ||
49 | rate = wl->conf.tx.basic_rate; | ||
50 | } else if (band == WL1271_SCAN_BAND_5_GHZ && wl1271_11a_enabled()) { | ||
51 | ieee_band = IEEE80211_BAND_5GHZ; | ||
52 | rate = wl->conf.tx.basic_rate_5; | ||
53 | } else | ||
54 | return -EINVAL; | ||
55 | |||
56 | if (wl->hw->wiphy->bands[ieee_band]->channels == NULL) | ||
57 | return -EINVAL; | ||
58 | |||
59 | channels = wl->hw->wiphy->bands[ieee_band]->channels; | ||
60 | n_ch = wl->hw->wiphy->bands[ieee_band]->n_channels; | ||
61 | |||
62 | if (test_bit(WL1271_FLAG_SCANNING, &wl->flags)) | ||
63 | return -EINVAL; | ||
64 | |||
65 | params = kzalloc(sizeof(*params), GFP_KERNEL); | ||
66 | if (!params) | ||
67 | return -ENOMEM; | ||
68 | |||
69 | params->params.rx_config_options = cpu_to_le32(CFG_RX_ALL_GOOD); | ||
70 | params->params.rx_filter_options = | ||
71 | cpu_to_le32(CFG_RX_PRSP_EN | CFG_RX_MGMT_EN | CFG_RX_BCN_EN); | ||
72 | 42 | ||
73 | if (!active_scan) | 43 | flags = req->channels[i]->flags; |
74 | scan_options |= WL1271_SCAN_OPT_PASSIVE; | ||
75 | if (high_prio) | ||
76 | scan_options |= WL1271_SCAN_OPT_PRIORITY_HIGH; | ||
77 | params->params.scan_options = cpu_to_le16(scan_options); | ||
78 | 44 | ||
79 | params->params.num_probe_requests = probe_requests; | 45 | if (!wl->scan.scanned_ch[i] && |
80 | params->params.tx_rate = cpu_to_le32(rate); | 46 | !(flags & IEEE80211_CHAN_DISABLED) && |
81 | params->params.tid_trigger = 0; | 47 | ((!!(flags & IEEE80211_CHAN_PASSIVE_SCAN)) == passive) && |
82 | params->params.scan_tag = WL1271_SCAN_DEFAULT_TAG; | 48 | (req->channels[i]->band == band)) { |
83 | 49 | ||
84 | if (band == WL1271_SCAN_BAND_DUAL) | 50 | wl1271_debug(DEBUG_SCAN, "band %d, center_freq %d ", |
85 | params->params.band = WL1271_SCAN_BAND_2_4_GHZ; | 51 | req->channels[i]->band, |
86 | else | 52 | req->channels[i]->center_freq); |
87 | params->params.band = band; | 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); | ||
88 | 62 | ||
89 | for (i = 0, j = 0; i < n_ch && i < WL1271_SCAN_MAX_CHANNELS; i++) { | 63 | channels[j].min_duration = |
90 | if (!(channels[i].flags & IEEE80211_CHAN_DISABLED)) { | ||
91 | params->channels[j].min_duration = | ||
92 | cpu_to_le32(WL1271_SCAN_CHAN_MIN_DURATION); | 64 | cpu_to_le32(WL1271_SCAN_CHAN_MIN_DURATION); |
93 | params->channels[j].max_duration = | 65 | channels[j].max_duration = |
94 | cpu_to_le32(WL1271_SCAN_CHAN_MAX_DURATION); | 66 | cpu_to_le32(WL1271_SCAN_CHAN_MAX_DURATION); |
95 | memset(¶ms->channels[j].bssid_lsb, 0xff, 4); | 67 | channels[j].early_termination = 0; |
96 | memset(¶ms->channels[j].bssid_msb, 0xff, 2); | 68 | channels[j].tx_power_att = WL1271_SCAN_CURRENT_TX_PWR; |
97 | params->channels[j].early_termination = 0; | 69 | channels[j].channel = req->channels[i]->hw_value; |
98 | params->channels[j].tx_power_att = | 70 | |
99 | WL1271_SCAN_CURRENT_TX_PWR; | 71 | memset(&channels[j].bssid_lsb, 0xff, 4); |
100 | params->channels[j].channel = channels[i].hw_value; | 72 | memset(&channels[j].bssid_msb, 0xff, 2); |
73 | |||
74 | /* Mark the channels we already used */ | ||
75 | wl->scan.scanned_ch[i] = true; | ||
76 | |||
101 | j++; | 77 | j++; |
102 | } | 78 | } |
103 | } | 79 | } |
104 | 80 | ||
105 | params->params.num_channels = j; | 81 | return j; |
82 | } | ||
106 | 83 | ||
107 | if (ssid_len && ssid) { | 84 | #define WL1271_NOTHING_TO_SCAN 1 |
108 | params->params.ssid_len = ssid_len; | 85 | |
109 | memcpy(params->params.ssid, ssid, ssid_len); | 86 | static 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; | ||
110 | } | 99 | } |
111 | 100 | ||
112 | ret = wl1271_cmd_build_probe_req(wl, ssid, ssid_len, | 101 | /* We always use high priority scans */ |
113 | req->ie, req->ie_len, ieee_band); | 102 | scan_options = WL1271_SCAN_OPT_PRIORITY_HIGH; |
114 | if (ret < 0) { | 103 | if(passive) |
115 | wl1271_error("PROBE request template failed"); | 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; | ||
116 | goto out; | 112 | goto out; |
117 | } | 113 | } |
118 | 114 | ||
119 | trigger = kzalloc(sizeof(*trigger), GFP_KERNEL); | 115 | cmd->params.tx_rate = cpu_to_le32(basic_rate); |
120 | if (!trigger) { | 116 | cmd->params.rx_config_options = cpu_to_le32(CFG_RX_ALL_GOOD); |
121 | ret = -ENOMEM; | 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"); | ||
122 | goto out; | 140 | goto out; |
123 | } | 141 | } |
124 | 142 | ||
125 | /* disable the timeout */ | 143 | /* disable the timeout */ |
126 | trigger->timeout = 0; | 144 | trigger->timeout = 0; |
127 | |||
128 | ret = wl1271_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger, | 145 | ret = wl1271_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger, |
129 | sizeof(*trigger), 0); | 146 | sizeof(*trigger), 0); |
130 | if (ret < 0) { | 147 | if (ret < 0) { |
@@ -132,60 +149,109 @@ int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len, | |||
132 | goto out; | 149 | goto out; |
133 | } | 150 | } |
134 | 151 | ||
135 | wl1271_dump(DEBUG_SCAN, "SCAN: ", params, sizeof(*params)); | 152 | wl1271_dump(DEBUG_SCAN, "SCAN: ", cmd, sizeof(*cmd)); |
136 | |||
137 | set_bit(WL1271_FLAG_SCANNING, &wl->flags); | ||
138 | if (wl1271_11a_enabled()) { | ||
139 | wl->scan.state = band; | ||
140 | if (band == WL1271_SCAN_BAND_DUAL) { | ||
141 | wl->scan.active = active_scan; | ||
142 | wl->scan.high_prio = high_prio; | ||
143 | wl->scan.probe_requests = probe_requests; | ||
144 | if (ssid_len && ssid) { | ||
145 | wl->scan.ssid_len = ssid_len; | ||
146 | memcpy(wl->scan.ssid, ssid, ssid_len); | ||
147 | } else | ||
148 | wl->scan.ssid_len = 0; | ||
149 | wl->scan.req = req; | ||
150 | } else | ||
151 | wl->scan.req = NULL; | ||
152 | } | ||
153 | 153 | ||
154 | ret = wl1271_cmd_send(wl, CMD_SCAN, params, sizeof(*params), 0); | 154 | ret = wl1271_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd), 0); |
155 | if (ret < 0) { | 155 | if (ret < 0) { |
156 | wl1271_error("SCAN failed"); | 156 | wl1271_error("SCAN failed"); |
157 | clear_bit(WL1271_FLAG_SCANNING, &wl->flags); | ||
158 | goto out; | 157 | goto out; |
159 | } | 158 | } |
160 | 159 | ||
161 | out: | 160 | out: |
162 | kfree(params); | 161 | kfree(cmd); |
163 | kfree(trigger); | 162 | kfree(trigger); |
164 | return ret; | 163 | return ret; |
165 | } | 164 | } |
166 | 165 | ||
167 | int wl1271_scan_complete(struct wl1271 *wl) | 166 | void wl1271_scan_stm(struct wl1271 *wl) |
168 | { | 167 | { |
169 | if (test_bit(WL1271_FLAG_SCANNING, &wl->flags)) { | 168 | int ret; |
170 | if (wl->scan.state == WL1271_SCAN_BAND_DUAL) { | 169 | |
171 | /* 2.4 GHz band scanned, scan 5 GHz band, pretend to | 170 | switch (wl->scan.state) { |
172 | * the wl1271_scan function that we are not scanning | 171 | case WL1271_SCAN_STATE_IDLE: |
173 | * as it checks that. | 172 | break; |
174 | */ | 173 | |
175 | clear_bit(WL1271_FLAG_SCANNING, &wl->flags); | 174 | case WL1271_SCAN_STATE_2GHZ_ACTIVE: |
176 | /* FIXME: ie missing! */ | 175 | ret = wl1271_scan_send(wl, IEEE80211_BAND_2GHZ, false, |
177 | wl1271_scan(wl, wl->scan.ssid, wl->scan.ssid_len, | 176 | wl->conf.tx.basic_rate); |
178 | wl->scan.req, | 177 | if (ret == WL1271_NOTHING_TO_SCAN) { |
179 | wl->scan.active, | 178 | wl->scan.state = WL1271_SCAN_STATE_2GHZ_PASSIVE; |
180 | wl->scan.high_prio, | 179 | wl1271_scan_stm(wl); |
181 | WL1271_SCAN_BAND_5_GHZ, | 180 | } |
182 | wl->scan.probe_requests); | 181 | |
183 | } else { | 182 | break; |
184 | mutex_unlock(&wl->mutex); | 183 | |
185 | ieee80211_scan_completed(wl->hw, false); | 184 | case WL1271_SCAN_STATE_2GHZ_PASSIVE: |
186 | mutex_lock(&wl->mutex); | 185 | ret = wl1271_scan_send(wl, IEEE80211_BAND_2GHZ, true, |
187 | clear_bit(WL1271_FLAG_SCANNING, &wl->flags); | 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); | ||
188 | } | 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; | ||
189 | } | 231 | } |
232 | } | ||
233 | |||
234 | int 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 | |||
190 | return 0; | 256 | return 0; |
191 | } | 257 | } |