Commit | Line | Data |
---|---|---|
30295c89 VM |
1 | //------------------------------------------------------------------------------ |
2 | // Copyright (c) 2004-2010 Atheros Communications Inc. | |
3 | // All rights reserved. | |
4 | // | |
5 | // | |
6 | // | |
7 | // Permission to use, copy, modify, and/or distribute this software for any | |
8 | // purpose with or without fee is hereby granted, provided that the above | |
9 | // copyright notice and this permission notice appear in all copies. | |
10 | // | |
11 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
12 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
13 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
14 | // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
15 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
16 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
17 | // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
18 | // | |
19 | // | |
20 | // | |
21 | // Author(s): ="Atheros" | |
22 | //------------------------------------------------------------------------------ | |
23 | ||
24 | #include "ar6000_drv.h" | |
25 | ||
26 | #define IWE_STREAM_ADD_EVENT(p1, p2, p3, p4, p5) \ | |
27 | iwe_stream_add_event((p1), (p2), (p3), (p4), (p5)) | |
28 | ||
29 | #define IWE_STREAM_ADD_POINT(p1, p2, p3, p4, p5) \ | |
30 | iwe_stream_add_point((p1), (p2), (p3), (p4), (p5)) | |
31 | ||
32 | #define IWE_STREAM_ADD_VALUE(p1, p2, p3, p4, p5, p6) \ | |
33 | iwe_stream_add_value((p1), (p2), (p3), (p4), (p5), (p6)) | |
34 | ||
f2ab1275 | 35 | static void ar6000_set_quality(struct iw_quality *iq, s8 rssi); |
30295c89 VM |
36 | extern unsigned int wmitimeout; |
37 | extern A_WAITQUEUE_HEAD arEvent; | |
38 | ||
39 | #if WIRELESS_EXT > 14 | |
40 | /* | |
41 | * Encode a WPA or RSN information element as a custom | |
42 | * element using the hostap format. | |
43 | */ | |
44 | static u_int | |
45 | encode_ie(void *buf, size_t bufsize, | |
46 | const u_int8_t *ie, size_t ielen, | |
47 | const char *leader, size_t leader_len) | |
48 | { | |
49 | u_int8_t *p; | |
50 | int i; | |
51 | ||
52 | if (bufsize < leader_len) | |
53 | return 0; | |
54 | p = buf; | |
55 | memcpy(p, leader, leader_len); | |
56 | bufsize -= leader_len; | |
57 | p += leader_len; | |
58 | for (i = 0; i < ielen && bufsize > 2; i++) | |
59 | { | |
60 | p += sprintf((char*)p, "%02x", ie[i]); | |
61 | bufsize -= 2; | |
62 | } | |
63 | return (i == ielen ? p - (u_int8_t *)buf : 0); | |
64 | } | |
65 | #endif /* WIRELESS_EXT > 14 */ | |
66 | ||
ab3655da | 67 | static u8 get_bss_phy_capability(bss_t *bss) |
30295c89 | 68 | { |
ab3655da | 69 | u8 capability = 0; |
30295c89 VM |
70 | struct ieee80211_common_ie *cie = &bss->ni_cie; |
71 | #define CHAN_IS_11A(x) (!((x >= 2412) && (x <= 2484))) | |
72 | if (CHAN_IS_11A(cie->ie_chan)) { | |
73 | if (cie->ie_htcap) { | |
74 | capability = WMI_11NA_CAPABILITY; | |
75 | } else { | |
76 | capability = WMI_11A_CAPABILITY; | |
77 | } | |
78 | } else if ((cie->ie_erp) || (cie->ie_xrates)) { | |
79 | if (cie->ie_htcap) { | |
80 | capability = WMI_11NG_CAPABILITY; | |
81 | } else { | |
82 | capability = WMI_11G_CAPABILITY; | |
83 | } | |
84 | } | |
85 | return capability; | |
86 | } | |
87 | ||
88 | void | |
89 | ar6000_scan_node(void *arg, bss_t *ni) | |
90 | { | |
91 | struct iw_event iwe; | |
92 | #if WIRELESS_EXT > 14 | |
93 | char buf[256]; | |
94 | #endif | |
95 | struct ar_giwscan_param *param; | |
4c42080f JP |
96 | char *current_ev; |
97 | char *end_buf; | |
30295c89 | 98 | struct ieee80211_common_ie *cie; |
4c42080f | 99 | char *current_val; |
f68057e6 | 100 | s32 j; |
e1ce2a3a | 101 | u32 rate_len, data_len = 0; |
30295c89 VM |
102 | |
103 | param = (struct ar_giwscan_param *)arg; | |
104 | ||
105 | current_ev = param->current_ev; | |
106 | end_buf = param->end_buf; | |
107 | ||
108 | cie = &ni->ni_cie; | |
109 | ||
110 | if ((end_buf - current_ev) > IW_EV_ADDR_LEN) | |
111 | { | |
112 | A_MEMZERO(&iwe, sizeof(iwe)); | |
113 | iwe.cmd = SIOCGIWAP; | |
114 | iwe.u.ap_addr.sa_family = ARPHRD_ETHER; | |
05209262 | 115 | memcpy(iwe.u.ap_addr.sa_data, ni->ni_macaddr, 6); |
30295c89 VM |
116 | current_ev = IWE_STREAM_ADD_EVENT(param->info, current_ev, end_buf, |
117 | &iwe, IW_EV_ADDR_LEN); | |
118 | } | |
119 | param->bytes_needed += IW_EV_ADDR_LEN; | |
120 | ||
121 | data_len = cie->ie_ssid[1] + IW_EV_POINT_LEN; | |
122 | if ((end_buf - current_ev) > data_len) | |
123 | { | |
124 | A_MEMZERO(&iwe, sizeof(iwe)); | |
125 | iwe.cmd = SIOCGIWESSID; | |
126 | iwe.u.data.flags = 1; | |
127 | iwe.u.data.length = cie->ie_ssid[1]; | |
128 | current_ev = IWE_STREAM_ADD_POINT(param->info, current_ev, end_buf, | |
129 | &iwe, (char*)&cie->ie_ssid[2]); | |
130 | } | |
131 | param->bytes_needed += data_len; | |
132 | ||
133 | if (cie->ie_capInfo & (IEEE80211_CAPINFO_ESS|IEEE80211_CAPINFO_IBSS)) { | |
134 | if ((end_buf - current_ev) > IW_EV_UINT_LEN) | |
135 | { | |
136 | A_MEMZERO(&iwe, sizeof(iwe)); | |
137 | iwe.cmd = SIOCGIWMODE; | |
138 | iwe.u.mode = cie->ie_capInfo & IEEE80211_CAPINFO_ESS ? | |
139 | IW_MODE_MASTER : IW_MODE_ADHOC; | |
140 | current_ev = IWE_STREAM_ADD_EVENT(param->info, current_ev, end_buf, | |
141 | &iwe, IW_EV_UINT_LEN); | |
142 | } | |
143 | param->bytes_needed += IW_EV_UINT_LEN; | |
144 | } | |
145 | ||
146 | if ((end_buf - current_ev) > IW_EV_FREQ_LEN) | |
147 | { | |
148 | A_MEMZERO(&iwe, sizeof(iwe)); | |
149 | iwe.cmd = SIOCGIWFREQ; | |
150 | iwe.u.freq.m = cie->ie_chan * 100000; | |
151 | iwe.u.freq.e = 1; | |
152 | current_ev = IWE_STREAM_ADD_EVENT(param->info, current_ev, end_buf, | |
153 | &iwe, IW_EV_FREQ_LEN); | |
154 | } | |
155 | param->bytes_needed += IW_EV_FREQ_LEN; | |
156 | ||
157 | if ((end_buf - current_ev) > IW_EV_QUAL_LEN) | |
158 | { | |
159 | A_MEMZERO(&iwe, sizeof(iwe)); | |
160 | iwe.cmd = IWEVQUAL; | |
161 | ar6000_set_quality(&iwe.u.qual, ni->ni_snr); | |
162 | current_ev = IWE_STREAM_ADD_EVENT(param->info, current_ev, end_buf, | |
163 | &iwe, IW_EV_QUAL_LEN); | |
164 | } | |
165 | param->bytes_needed += IW_EV_QUAL_LEN; | |
166 | ||
167 | if ((end_buf - current_ev) > IW_EV_POINT_LEN) | |
168 | { | |
169 | A_MEMZERO(&iwe, sizeof(iwe)); | |
170 | iwe.cmd = SIOCGIWENCODE; | |
171 | if (cie->ie_capInfo & IEEE80211_CAPINFO_PRIVACY) { | |
172 | iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; | |
173 | } else { | |
174 | iwe.u.data.flags = IW_ENCODE_DISABLED; | |
175 | } | |
176 | iwe.u.data.length = 0; | |
177 | current_ev = IWE_STREAM_ADD_POINT(param->info, current_ev, end_buf, | |
178 | &iwe, ""); | |
179 | } | |
180 | param->bytes_needed += IW_EV_POINT_LEN; | |
181 | ||
182 | /* supported bit rate */ | |
183 | A_MEMZERO(&iwe, sizeof(iwe)); | |
184 | iwe.cmd = SIOCGIWRATE; | |
185 | iwe.u.bitrate.fixed = 0; | |
186 | iwe.u.bitrate.disabled = 0; | |
187 | iwe.u.bitrate.value = 0; | |
188 | current_val = current_ev + IW_EV_LCP_LEN; | |
189 | param->bytes_needed += IW_EV_LCP_LEN; | |
190 | ||
191 | if (cie->ie_rates != NULL) { | |
192 | rate_len = cie->ie_rates[1]; | |
193 | data_len = (rate_len * (IW_EV_PARAM_LEN - IW_EV_LCP_LEN)); | |
194 | if ((end_buf - current_ev) > data_len) | |
195 | { | |
196 | for (j = 0; j < rate_len; j++) { | |
197 | unsigned char val; | |
198 | val = cie->ie_rates[2 + j]; | |
199 | iwe.u.bitrate.value = | |
200 | (val >= 0x80)? ((val - 0x80) * 500000): (val * 500000); | |
201 | current_val = IWE_STREAM_ADD_VALUE(param->info, current_ev, | |
202 | current_val, end_buf, | |
203 | &iwe, IW_EV_PARAM_LEN); | |
204 | } | |
205 | } | |
206 | param->bytes_needed += data_len; | |
207 | } | |
208 | ||
209 | if (cie->ie_xrates != NULL) { | |
210 | rate_len = cie->ie_xrates[1]; | |
211 | data_len = (rate_len * (IW_EV_PARAM_LEN - IW_EV_LCP_LEN)); | |
212 | if ((end_buf - current_ev) > data_len) | |
213 | { | |
214 | for (j = 0; j < rate_len; j++) { | |
215 | unsigned char val; | |
216 | val = cie->ie_xrates[2 + j]; | |
217 | iwe.u.bitrate.value = | |
218 | (val >= 0x80)? ((val - 0x80) * 500000): (val * 500000); | |
219 | current_val = IWE_STREAM_ADD_VALUE(param->info, current_ev, | |
220 | current_val, end_buf, | |
221 | &iwe, IW_EV_PARAM_LEN); | |
222 | } | |
223 | } | |
224 | param->bytes_needed += data_len; | |
225 | } | |
226 | /* remove fixed header if no rates were added */ | |
227 | if ((current_val - current_ev) > IW_EV_LCP_LEN) | |
228 | current_ev = current_val; | |
229 | ||
230 | #if WIRELESS_EXT >= 18 | |
231 | /* IE */ | |
232 | if (cie->ie_wpa != NULL) { | |
233 | data_len = cie->ie_wpa[1] + 2 + IW_EV_POINT_LEN; | |
234 | if ((end_buf - current_ev) > data_len) | |
235 | { | |
236 | A_MEMZERO(&iwe, sizeof(iwe)); | |
237 | iwe.cmd = IWEVGENIE; | |
238 | iwe.u.data.length = cie->ie_wpa[1] + 2; | |
239 | current_ev = IWE_STREAM_ADD_POINT(param->info, current_ev, end_buf, | |
240 | &iwe, (char*)cie->ie_wpa); | |
241 | } | |
242 | param->bytes_needed += data_len; | |
243 | } | |
244 | ||
245 | if (cie->ie_rsn != NULL && cie->ie_rsn[0] == IEEE80211_ELEMID_RSN) { | |
246 | data_len = cie->ie_rsn[1] + 2 + IW_EV_POINT_LEN; | |
247 | if ((end_buf - current_ev) > data_len) | |
248 | { | |
249 | A_MEMZERO(&iwe, sizeof(iwe)); | |
250 | iwe.cmd = IWEVGENIE; | |
251 | iwe.u.data.length = cie->ie_rsn[1] + 2; | |
252 | current_ev = IWE_STREAM_ADD_POINT(param->info, current_ev, end_buf, | |
253 | &iwe, (char*)cie->ie_rsn); | |
254 | } | |
255 | param->bytes_needed += data_len; | |
256 | } | |
257 | ||
258 | #endif /* WIRELESS_EXT >= 18 */ | |
259 | ||
260 | if ((end_buf - current_ev) > IW_EV_CHAR_LEN) | |
261 | { | |
262 | /* protocol */ | |
263 | A_MEMZERO(&iwe, sizeof(iwe)); | |
264 | iwe.cmd = SIOCGIWNAME; | |
265 | switch (get_bss_phy_capability(ni)) { | |
266 | case WMI_11A_CAPABILITY: | |
267 | snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11a"); | |
268 | break; | |
269 | case WMI_11G_CAPABILITY: | |
270 | snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11g"); | |
271 | break; | |
272 | case WMI_11NA_CAPABILITY: | |
273 | snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11na"); | |
274 | break; | |
275 | case WMI_11NG_CAPABILITY: | |
276 | snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11ng"); | |
277 | break; | |
278 | default: | |
279 | snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11b"); | |
280 | break; | |
281 | } | |
282 | current_ev = IWE_STREAM_ADD_EVENT(param->info, current_ev, end_buf, | |
283 | &iwe, IW_EV_CHAR_LEN); | |
284 | } | |
285 | param->bytes_needed += IW_EV_CHAR_LEN; | |
286 | ||
287 | #if WIRELESS_EXT > 14 | |
288 | A_MEMZERO(&iwe, sizeof(iwe)); | |
289 | iwe.cmd = IWEVCUSTOM; | |
290 | iwe.u.data.length = snprintf(buf, sizeof(buf), "bcn_int=%d", cie->ie_beaconInt); | |
291 | data_len = iwe.u.data.length + IW_EV_POINT_LEN; | |
292 | if ((end_buf - current_ev) > data_len) | |
293 | { | |
294 | current_ev = IWE_STREAM_ADD_POINT(param->info, current_ev, end_buf, | |
295 | &iwe, buf); | |
296 | } | |
297 | param->bytes_needed += data_len; | |
298 | ||
299 | #if WIRELESS_EXT < 18 | |
300 | if (cie->ie_wpa != NULL) { | |
301 | static const char wpa_leader[] = "wpa_ie="; | |
302 | data_len = (sizeof(wpa_leader) - 1) + ((cie->ie_wpa[1]+2) * 2) + IW_EV_POINT_LEN; | |
303 | if ((end_buf - current_ev) > data_len) | |
304 | { | |
305 | A_MEMZERO(&iwe, sizeof(iwe)); | |
306 | iwe.cmd = IWEVCUSTOM; | |
307 | iwe.u.data.length = encode_ie(buf, sizeof(buf), cie->ie_wpa, | |
308 | cie->ie_wpa[1]+2, | |
309 | wpa_leader, sizeof(wpa_leader)-1); | |
310 | ||
311 | if (iwe.u.data.length != 0) { | |
312 | current_ev = IWE_STREAM_ADD_POINT(param->info, current_ev, | |
313 | end_buf, &iwe, buf); | |
314 | } | |
315 | } | |
316 | param->bytes_needed += data_len; | |
317 | } | |
318 | ||
319 | if (cie->ie_rsn != NULL && cie->ie_rsn[0] == IEEE80211_ELEMID_RSN) { | |
320 | static const char rsn_leader[] = "rsn_ie="; | |
321 | data_len = (sizeof(rsn_leader) - 1) + ((cie->ie_rsn[1]+2) * 2) + IW_EV_POINT_LEN; | |
322 | if ((end_buf - current_ev) > data_len) | |
323 | { | |
324 | A_MEMZERO(&iwe, sizeof(iwe)); | |
325 | iwe.cmd = IWEVCUSTOM; | |
326 | iwe.u.data.length = encode_ie(buf, sizeof(buf), cie->ie_rsn, | |
327 | cie->ie_rsn[1]+2, | |
328 | rsn_leader, sizeof(rsn_leader)-1); | |
329 | ||
330 | if (iwe.u.data.length != 0) { | |
331 | current_ev = IWE_STREAM_ADD_POINT(param->info, current_ev, | |
332 | end_buf, &iwe, buf); | |
333 | } | |
334 | } | |
335 | param->bytes_needed += data_len; | |
336 | } | |
337 | #endif /* WIRELESS_EXT < 18 */ | |
338 | ||
339 | if (cie->ie_wmm != NULL) { | |
340 | static const char wmm_leader[] = "wmm_ie="; | |
341 | data_len = (sizeof(wmm_leader) - 1) + ((cie->ie_wmm[1]+2) * 2) + IW_EV_POINT_LEN; | |
342 | if ((end_buf - current_ev) > data_len) | |
343 | { | |
344 | A_MEMZERO(&iwe, sizeof(iwe)); | |
345 | iwe.cmd = IWEVCUSTOM; | |
346 | iwe.u.data.length = encode_ie(buf, sizeof(buf), cie->ie_wmm, | |
347 | cie->ie_wmm[1]+2, | |
348 | wmm_leader, sizeof(wmm_leader)-1); | |
349 | if (iwe.u.data.length != 0) { | |
350 | current_ev = IWE_STREAM_ADD_POINT(param->info, current_ev, | |
351 | end_buf, &iwe, buf); | |
352 | } | |
353 | } | |
354 | param->bytes_needed += data_len; | |
355 | } | |
356 | ||
357 | if (cie->ie_ath != NULL) { | |
358 | static const char ath_leader[] = "ath_ie="; | |
359 | data_len = (sizeof(ath_leader) - 1) + ((cie->ie_ath[1]+2) * 2) + IW_EV_POINT_LEN; | |
360 | if ((end_buf - current_ev) > data_len) | |
361 | { | |
362 | A_MEMZERO(&iwe, sizeof(iwe)); | |
363 | iwe.cmd = IWEVCUSTOM; | |
364 | iwe.u.data.length = encode_ie(buf, sizeof(buf), cie->ie_ath, | |
365 | cie->ie_ath[1]+2, | |
366 | ath_leader, sizeof(ath_leader)-1); | |
367 | if (iwe.u.data.length != 0) { | |
368 | current_ev = IWE_STREAM_ADD_POINT(param->info, current_ev, | |
369 | end_buf, &iwe, buf); | |
370 | } | |
371 | } | |
372 | param->bytes_needed += data_len; | |
373 | } | |
374 | ||
375 | #ifdef WAPI_ENABLE | |
376 | if (cie->ie_wapi != NULL) { | |
377 | static const char wapi_leader[] = "wapi_ie="; | |
378 | data_len = (sizeof(wapi_leader) - 1) + ((cie->ie_wapi[1] + 2) * 2) + IW_EV_POINT_LEN; | |
379 | if ((end_buf - current_ev) > data_len) { | |
380 | A_MEMZERO(&iwe, sizeof(iwe)); | |
381 | iwe.cmd = IWEVCUSTOM; | |
382 | iwe.u.data.length = encode_ie(buf, sizeof(buf), cie->ie_wapi, | |
383 | cie->ie_wapi[1] + 2, | |
384 | wapi_leader, sizeof(wapi_leader) - 1); | |
385 | if (iwe.u.data.length != 0) { | |
386 | current_ev = IWE_STREAM_ADD_POINT(param->info, current_ev, | |
387 | end_buf, &iwe, buf); | |
388 | } | |
389 | } | |
390 | param->bytes_needed += data_len; | |
391 | } | |
392 | #endif /* WAPI_ENABLE */ | |
393 | ||
394 | #endif /* WIRELESS_EXT > 14 */ | |
395 | ||
396 | #if WIRELESS_EXT >= 18 | |
397 | if (cie->ie_wsc != NULL) { | |
398 | data_len = (cie->ie_wsc[1] + 2) + IW_EV_POINT_LEN; | |
399 | if ((end_buf - current_ev) > data_len) | |
400 | { | |
401 | A_MEMZERO(&iwe, sizeof(iwe)); | |
402 | iwe.cmd = IWEVGENIE; | |
403 | iwe.u.data.length = cie->ie_wsc[1] + 2; | |
404 | current_ev = IWE_STREAM_ADD_POINT(param->info, current_ev, end_buf, | |
405 | &iwe, (char*)cie->ie_wsc); | |
406 | } | |
407 | param->bytes_needed += data_len; | |
408 | } | |
409 | #endif /* WIRELESS_EXT >= 18 */ | |
410 | ||
411 | param->current_ev = current_ev; | |
412 | } | |
413 | ||
414 | int | |
415 | ar6000_ioctl_giwscan(struct net_device *dev, | |
416 | struct iw_request_info *info, | |
417 | struct iw_point *data, char *extra) | |
418 | { | |
a71f0bf6 | 419 | struct ar6_softc *ar = (struct ar6_softc *)ar6k_priv(dev); |
30295c89 VM |
420 | struct ar_giwscan_param param; |
421 | ||
4f69cef0 | 422 | if (is_iwioctl_allowed(ar->arNextMode, info->cmd) != 0) { |
30295c89 VM |
423 | A_PRINTF("wext_ioctl: cmd=0x%x not allowed in this mode\n", info->cmd); |
424 | return -EOPNOTSUPP; | |
425 | } | |
426 | ||
427 | if (ar->arWlanState == WLAN_DISABLED) { | |
428 | return -EIO; | |
429 | } | |
430 | ||
1071a134 | 431 | if (ar->arWmiReady == false) { |
30295c89 VM |
432 | return -EIO; |
433 | } | |
434 | ||
435 | param.current_ev = extra; | |
436 | param.end_buf = extra + data->length; | |
437 | param.bytes_needed = 0; | |
438 | param.info = info; | |
439 | ||
440 | /* Translate data to WE format */ | |
441 | wmi_iterate_nodes(ar->arWmi, ar6000_scan_node, ¶m); | |
442 | ||
443 | /* check if bytes needed is greater than bytes consumed */ | |
444 | if (param.bytes_needed > (param.current_ev - extra)) | |
445 | { | |
446 | /* Request one byte more than needed, because when "data->length" equals bytes_needed, | |
447 | it is not possible to add the last event data as all iwe_stream_add_xxxxx() functions | |
448 | checks whether (cur_ptr + ev_len) < end_ptr, due to this one more retry would happen*/ | |
449 | data->length = param.bytes_needed + 1; | |
450 | ||
451 | return -E2BIG; | |
452 | } | |
453 | ||
454 | return 0; | |
455 | } | |
456 | ||
457 | extern int reconnect_flag; | |
458 | /* SIOCSIWESSID */ | |
459 | static int | |
460 | ar6000_ioctl_siwessid(struct net_device *dev, | |
461 | struct iw_request_info *info, | |
462 | struct iw_point *data, char *ssid) | |
463 | { | |
a71f0bf6 | 464 | struct ar6_softc *ar = (struct ar6_softc *)ar6k_priv(dev); |
1f4c34bd | 465 | int status; |
ab3655da JP |
466 | u8 arNetworkType; |
467 | u8 prevMode = ar->arNetworkType; | |
30295c89 | 468 | |
4f69cef0 | 469 | if (is_iwioctl_allowed(ar->arNextMode, info->cmd) != 0) { |
30295c89 VM |
470 | A_PRINTF("wext_ioctl: cmd=0x%x not allowed in this mode\n", info->cmd); |
471 | return -EOPNOTSUPP; | |
472 | } | |
473 | ||
474 | if (ar->bIsDestroyProgress) { | |
475 | return -EBUSY; | |
476 | } | |
477 | ||
478 | if (ar->arWlanState == WLAN_DISABLED) { | |
479 | return -EIO; | |
480 | } | |
481 | ||
1071a134 | 482 | if (ar->arWmiReady == false) { |
30295c89 VM |
483 | return -EIO; |
484 | } | |
485 | ||
486 | #if defined(WIRELESS_EXT) | |
487 | if (WIRELESS_EXT >= 20) { | |
488 | data->length += 1; | |
489 | } | |
490 | #endif | |
491 | ||
492 | /* | |
493 | * iwconfig passes a null terminated string with length including this | |
494 | * so we need to account for this | |
495 | */ | |
496 | if (data->flags && (!data->length || (data->length == 1) || | |
497 | ((data->length - 1) > sizeof(ar->arSsid)))) | |
498 | { | |
499 | /* | |
500 | * ssid is invalid | |
501 | */ | |
502 | return -EINVAL; | |
503 | } | |
504 | ||
505 | if (ar->arNextMode == AP_NETWORK) { | |
506 | /* SSID change for AP network - Will take effect on commit */ | |
395e1cae | 507 | if(memcmp(ar->arSsid,ssid,32) != 0) { |
30295c89 | 508 | ar->arSsidLen = data->length - 1; |
05209262 | 509 | memcpy(ar->arSsid, ssid, ar->arSsidLen); |
30295c89 VM |
510 | ar->ap_profile_flag = 1; /* There is a change in profile */ |
511 | } | |
512 | return 0; | |
513 | } else if(ar->arNetworkType == AP_NETWORK) { | |
ab3655da | 514 | u8 ctr; |
30295c89 VM |
515 | struct sk_buff *skb; |
516 | ||
517 | /* We are switching from AP to STA | IBSS mode, cleanup the AP state */ | |
518 | for (ctr=0; ctr < AP_MAX_NUM_STA; ctr++) { | |
519 | remove_sta(ar, ar->sta_list[ctr].mac, 0); | |
520 | } | |
521 | A_MUTEX_LOCK(&ar->mcastpsqLock); | |
522 | while (!A_NETBUF_QUEUE_EMPTY(&ar->mcastpsq)) { | |
523 | skb = A_NETBUF_DEQUEUE(&ar->mcastpsq); | |
524 | A_NETBUF_FREE(skb); | |
525 | } | |
526 | A_MUTEX_UNLOCK(&ar->mcastpsqLock); | |
527 | } | |
528 | ||
529 | /* Added for bug 25178, return an IOCTL error instead of target returning | |
530 | Illegal parameter error when either the BSSID or channel is missing | |
531 | and we cannot scan during connect. | |
532 | */ | |
533 | if (data->flags) { | |
1071a134 | 534 | if (ar->arSkipScan == true && |
30295c89 VM |
535 | (ar->arChannelHint == 0 || |
536 | (!ar->arReqBssid[0] && !ar->arReqBssid[1] && !ar->arReqBssid[2] && | |
537 | !ar->arReqBssid[3] && !ar->arReqBssid[4] && !ar->arReqBssid[5]))) | |
538 | { | |
539 | return -EINVAL; | |
540 | } | |
541 | } | |
542 | ||
543 | if (down_interruptible(&ar->arSem)) { | |
544 | return -ERESTARTSYS; | |
545 | } | |
546 | ||
547 | if (ar->bIsDestroyProgress || ar->arWlanState == WLAN_DISABLED) { | |
548 | up(&ar->arSem); | |
549 | return -EBUSY; | |
550 | } | |
551 | ||
552 | if (ar->arTxPending[wmi_get_control_ep(ar->arWmi)]) { | |
553 | /* | |
554 | * sleep until the command queue drains | |
555 | */ | |
556 | wait_event_interruptible_timeout(arEvent, | |
557 | ar->arTxPending[wmi_get_control_ep(ar->arWmi)] == 0, wmitimeout * HZ); | |
558 | if (signal_pending(current)) { | |
559 | return -EINTR; | |
560 | } | |
561 | } | |
562 | ||
563 | if (!data->flags) { | |
564 | arNetworkType = ar->arNetworkType; | |
565 | #ifdef ATH6K_CONFIG_CFG80211 | |
566 | if (ar->arConnected) { | |
567 | #endif /* ATH6K_CONFIG_CFG80211 */ | |
568 | ar6000_init_profile_info(ar); | |
569 | #ifdef ATH6K_CONFIG_CFG80211 | |
570 | } | |
571 | #endif /* ATH6K_CONFIG_CFG80211 */ | |
572 | ar->arNetworkType = arNetworkType; | |
573 | } | |
574 | ||
575 | /* Update the arNetworkType */ | |
576 | ar->arNetworkType = ar->arNextMode; | |
577 | ||
30295c89 | 578 | if ((prevMode != AP_NETWORK) && |
83195cc8 VM |
579 | ((ar->arSsidLen) || |
580 | ((ar->arSsidLen == 0) && (ar->arConnected || ar->arConnectPending)) || | |
581 | (!data->flags))) | |
30295c89 VM |
582 | { |
583 | if ((!data->flags) || | |
395e1cae | 584 | (memcmp(ar->arSsid, ssid, ar->arSsidLen) != 0) || |
30295c89 VM |
585 | (ar->arSsidLen != (data->length - 1))) |
586 | { | |
587 | /* | |
588 | * SSID set previously or essid off has been issued. | |
589 | * | |
590 | * Disconnect Command is issued in two cases after wmi is ready | |
591 | * (1) ssid is different from the previous setting | |
592 | * (2) essid off has been issued | |
593 | * | |
594 | */ | |
1071a134 | 595 | if (ar->arWmiReady == true) { |
30295c89 VM |
596 | reconnect_flag = 0; |
597 | status = wmi_setPmkid_cmd(ar->arWmi, ar->arBssid, NULL, 0); | |
83195cc8 | 598 | ar6000_disconnect(ar); |
30295c89 VM |
599 | A_MEMZERO(ar->arSsid, sizeof(ar->arSsid)); |
600 | ar->arSsidLen = 0; | |
1071a134 | 601 | if (ar->arSkipScan == false) { |
30295c89 VM |
602 | A_MEMZERO(ar->arReqBssid, sizeof(ar->arReqBssid)); |
603 | } | |
604 | if (!data->flags) { | |
605 | up(&ar->arSem); | |
606 | return 0; | |
607 | } | |
608 | } else { | |
609 | up(&ar->arSem); | |
610 | } | |
611 | } | |
612 | else | |
613 | { | |
614 | /* | |
615 | * SSID is same, so we assume profile hasn't changed. | |
616 | * If the interface is up and wmi is ready, we issue | |
617 | * a reconnect cmd. Issue a reconnect only we are already | |
618 | * connected. | |
619 | */ | |
1071a134 | 620 | if((ar->arConnected == true) && (ar->arWmiReady == true)) |
30295c89 | 621 | { |
1071a134 | 622 | reconnect_flag = true; |
30295c89 VM |
623 | status = wmi_reconnect_cmd(ar->arWmi,ar->arReqBssid, |
624 | ar->arChannelHint); | |
625 | up(&ar->arSem); | |
a1d46529 | 626 | if (status) { |
30295c89 VM |
627 | return -EIO; |
628 | } | |
629 | return 0; | |
630 | } | |
631 | else{ | |
632 | /* | |
633 | * Dont return if connect is pending. | |
634 | */ | |
635 | if(!(ar->arConnectPending)) { | |
636 | up(&ar->arSem); | |
637 | return 0; | |
638 | } | |
639 | } | |
640 | } | |
641 | } | |
642 | ||
643 | ar->arSsidLen = data->length - 1; | |
05209262 | 644 | memcpy(ar->arSsid, ssid, ar->arSsidLen); |
30295c89 | 645 | |
4f69cef0 | 646 | if (ar6000_connect_to_ap(ar)!= 0) { |
30295c89 VM |
647 | up(&ar->arSem); |
648 | return -EIO; | |
649 | }else{ | |
650 | up(&ar->arSem); | |
651 | } | |
652 | return 0; | |
653 | } | |
654 | ||
655 | /* SIOCGIWESSID */ | |
656 | static int | |
657 | ar6000_ioctl_giwessid(struct net_device *dev, | |
658 | struct iw_request_info *info, | |
659 | struct iw_point *data, char *essid) | |
660 | { | |
a71f0bf6 | 661 | struct ar6_softc *ar = (struct ar6_softc *)ar6k_priv(dev); |
30295c89 | 662 | |
4f69cef0 | 663 | if (is_iwioctl_allowed(ar->arNextMode, info->cmd) != 0) { |
30295c89 VM |
664 | A_PRINTF("wext_ioctl: cmd=0x%x not allowed in this mode\n", info->cmd); |
665 | return -EOPNOTSUPP; | |
666 | } | |
667 | ||
668 | if (ar->arWlanState == WLAN_DISABLED) { | |
669 | return -EIO; | |
670 | } | |
671 | ||
672 | if (!ar->arSsidLen) { | |
673 | return -EINVAL; | |
674 | } | |
675 | ||
676 | data->flags = 1; | |
677 | data->length = ar->arSsidLen; | |
05209262 | 678 | memcpy(essid, ar->arSsid, ar->arSsidLen); |
30295c89 VM |
679 | |
680 | return 0; | |
681 | } | |
682 | ||
683 | ||
a71f0bf6 | 684 | void ar6000_install_static_wep_keys(struct ar6_softc *ar) |
30295c89 | 685 | { |
ab3655da JP |
686 | u8 index; |
687 | u8 keyUsage; | |
30295c89 VM |
688 | |
689 | for (index = WMI_MIN_KEY_INDEX; index <= WMI_MAX_KEY_INDEX; index++) { | |
690 | if (ar->arWepKeyList[index].arKeyLen) { | |
691 | keyUsage = GROUP_USAGE; | |
692 | if (index == ar->arDefTxKeyIndex) { | |
693 | keyUsage |= TX_USAGE; | |
694 | } | |
695 | wmi_addKey_cmd(ar->arWmi, | |
696 | index, | |
697 | WEP_CRYPT, | |
698 | keyUsage, | |
699 | ar->arWepKeyList[index].arKeyLen, | |
700 | NULL, | |
701 | ar->arWepKeyList[index].arKey, KEY_OP_INIT_VAL, NULL, | |
702 | NO_SYNC_WMIFLAG); | |
703 | } | |
704 | } | |
705 | } | |
706 | ||
707 | /* | |
708 | * SIOCSIWRATE | |
709 | */ | |
710 | int | |
711 | ar6000_ioctl_siwrate(struct net_device *dev, | |
712 | struct iw_request_info *info, | |
713 | struct iw_param *rrq, char *extra) | |
714 | { | |
a71f0bf6 | 715 | struct ar6_softc *ar = (struct ar6_softc *)ar6k_priv(dev); |
e1ce2a3a | 716 | u32 kbps; |
f2ab1275 | 717 | s8 rate_idx; |
30295c89 | 718 | |
4f69cef0 | 719 | if (is_iwioctl_allowed(ar->arNextMode, info->cmd) != 0) { |
30295c89 VM |
720 | A_PRINTF("wext_ioctl: cmd=0x%x not allowed in this mode\n", info->cmd); |
721 | return -EOPNOTSUPP; | |
722 | } | |
723 | ||
724 | if (rrq->fixed) { | |
725 | kbps = rrq->value / 1000; /* rrq->value is in bps */ | |
726 | } else { | |
727 | kbps = -1; /* -1 indicates auto rate */ | |
728 | } | |
4f69cef0 | 729 | if(kbps != -1 && wmi_validate_bitrate(ar->arWmi, kbps, &rate_idx) != 0) |
30295c89 VM |
730 | { |
731 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("BitRate is not Valid %d\n", kbps)); | |
732 | return -EINVAL; | |
733 | } | |
734 | ar->arBitRate = kbps; | |
1071a134 | 735 | if(ar->arWmiReady == true) |
30295c89 | 736 | { |
4f69cef0 | 737 | if (wmi_set_bitrate_cmd(ar->arWmi, kbps, -1, -1) != 0) { |
30295c89 VM |
738 | return -EINVAL; |
739 | } | |
740 | } | |
741 | return 0; | |
742 | } | |
743 | ||
744 | /* | |
745 | * SIOCGIWRATE | |
746 | */ | |
747 | int | |
748 | ar6000_ioctl_giwrate(struct net_device *dev, | |
749 | struct iw_request_info *info, | |
750 | struct iw_param *rrq, char *extra) | |
751 | { | |
a71f0bf6 | 752 | struct ar6_softc *ar = (struct ar6_softc *)ar6k_priv(dev); |
30295c89 VM |
753 | int ret = 0; |
754 | ||
4f69cef0 | 755 | if (is_iwioctl_allowed(ar->arNextMode, info->cmd) != 0) { |
30295c89 VM |
756 | A_PRINTF("wext_ioctl: cmd=0x%x not allowed in this mode\n", info->cmd); |
757 | return -EOPNOTSUPP; | |
758 | } | |
759 | ||
760 | if (ar->bIsDestroyProgress) { | |
761 | return -EBUSY; | |
762 | } | |
763 | ||
764 | if (ar->arWlanState == WLAN_DISABLED) { | |
765 | return -EIO; | |
766 | } | |
767 | ||
1071a134 | 768 | if ((ar->arNextMode != AP_NETWORK && !ar->arConnected) || ar->arWmiReady == false) { |
30295c89 VM |
769 | rrq->value = 1000 * 1000; |
770 | return 0; | |
771 | } | |
772 | ||
773 | if (down_interruptible(&ar->arSem)) { | |
774 | return -ERESTARTSYS; | |
775 | } | |
776 | ||
777 | if (ar->bIsDestroyProgress || ar->arWlanState == WLAN_DISABLED) { | |
778 | up(&ar->arSem); | |
779 | return -EBUSY; | |
780 | } | |
781 | ||
782 | ar->arBitRate = 0xFFFF; | |
4f69cef0 | 783 | if (wmi_get_bitrate_cmd(ar->arWmi) != 0) { |
30295c89 VM |
784 | up(&ar->arSem); |
785 | return -EIO; | |
786 | } | |
787 | wait_event_interruptible_timeout(arEvent, ar->arBitRate != 0xFFFF, wmitimeout * HZ); | |
788 | if (signal_pending(current)) { | |
789 | ret = -EINTR; | |
790 | } | |
791 | /* If the interface is down or wmi is not ready or the target is not | |
792 | connected - return the value stored in the device structure */ | |
793 | if (!ret) { | |
794 | if (ar->arBitRate == -1) { | |
1071a134 | 795 | rrq->fixed = true; |
30295c89 VM |
796 | rrq->value = 0; |
797 | } else { | |
798 | rrq->value = ar->arBitRate * 1000; | |
799 | } | |
800 | } | |
801 | ||
802 | up(&ar->arSem); | |
803 | ||
804 | return ret; | |
805 | } | |
806 | ||
807 | /* | |
808 | * SIOCSIWTXPOW | |
809 | */ | |
810 | static int | |
811 | ar6000_ioctl_siwtxpow(struct net_device *dev, | |
812 | struct iw_request_info *info, | |
813 | struct iw_param *rrq, char *extra) | |
814 | { | |
a71f0bf6 | 815 | struct ar6_softc *ar = (struct ar6_softc *)ar6k_priv(dev); |
ab3655da | 816 | u8 dbM; |
30295c89 | 817 | |
4f69cef0 | 818 | if (is_iwioctl_allowed(ar->arNextMode, info->cmd) != 0) { |
30295c89 VM |
819 | A_PRINTF("wext_ioctl: cmd=0x%x not allowed in this mode\n", info->cmd); |
820 | return -EOPNOTSUPP; | |
821 | } | |
822 | ||
823 | if (ar->arWlanState == WLAN_DISABLED) { | |
824 | return -EIO; | |
825 | } | |
826 | ||
827 | if (rrq->disabled) { | |
828 | return -EOPNOTSUPP; | |
829 | } | |
830 | ||
831 | if (rrq->fixed) { | |
832 | if (rrq->flags != IW_TXPOW_DBM) { | |
833 | return -EOPNOTSUPP; | |
834 | } | |
835 | ar->arTxPwr= dbM = rrq->value; | |
1071a134 | 836 | ar->arTxPwrSet = true; |
30295c89 VM |
837 | } else { |
838 | ar->arTxPwr = dbM = 0; | |
1071a134 | 839 | ar->arTxPwrSet = false; |
30295c89 | 840 | } |
1071a134 | 841 | if(ar->arWmiReady == true) |
30295c89 VM |
842 | { |
843 | AR_DEBUG_PRINTF(ATH_DEBUG_WLAN_TX,("Set tx pwr cmd %d dbM\n", dbM)); | |
844 | wmi_set_txPwr_cmd(ar->arWmi, dbM); | |
845 | } | |
846 | return 0; | |
847 | } | |
848 | ||
849 | /* | |
850 | * SIOCGIWTXPOW | |
851 | */ | |
852 | int | |
853 | ar6000_ioctl_giwtxpow(struct net_device *dev, | |
854 | struct iw_request_info *info, | |
855 | struct iw_param *rrq, char *extra) | |
856 | { | |
a71f0bf6 | 857 | struct ar6_softc *ar = (struct ar6_softc *)ar6k_priv(dev); |
30295c89 VM |
858 | int ret = 0; |
859 | ||
4f69cef0 | 860 | if (is_iwioctl_allowed(ar->arNextMode, info->cmd) != 0) { |
30295c89 VM |
861 | A_PRINTF("wext_ioctl: cmd=0x%x not allowed in this mode\n", info->cmd); |
862 | return -EOPNOTSUPP; | |
863 | } | |
864 | ||
865 | if (ar->bIsDestroyProgress) { | |
866 | return -EBUSY; | |
867 | } | |
868 | ||
869 | if (ar->arWlanState == WLAN_DISABLED) { | |
870 | return -EIO; | |
871 | } | |
872 | ||
873 | if (down_interruptible(&ar->arSem)) { | |
874 | return -ERESTARTSYS; | |
875 | } | |
876 | ||
877 | if (ar->bIsDestroyProgress) { | |
878 | up(&ar->arSem); | |
879 | return -EBUSY; | |
880 | } | |
881 | ||
1071a134 | 882 | if((ar->arWmiReady == true) && (ar->arConnected == true)) |
30295c89 VM |
883 | { |
884 | ar->arTxPwr = 0; | |
885 | ||
4f69cef0 | 886 | if (wmi_get_txPwr_cmd(ar->arWmi) != 0) { |
30295c89 VM |
887 | up(&ar->arSem); |
888 | return -EIO; | |
889 | } | |
890 | ||
891 | wait_event_interruptible_timeout(arEvent, ar->arTxPwr != 0, wmitimeout * HZ); | |
892 | ||
893 | if (signal_pending(current)) { | |
894 | ret = -EINTR; | |
895 | } | |
896 | } | |
897 | /* If the interace is down or wmi is not ready or target is not connected | |
898 | then return value stored in the device structure */ | |
899 | ||
900 | if (!ret) { | |
1071a134 JP |
901 | if (ar->arTxPwrSet == true) { |
902 | rrq->fixed = true; | |
30295c89 VM |
903 | } |
904 | rrq->value = ar->arTxPwr; | |
905 | rrq->flags = IW_TXPOW_DBM; | |
906 | // | |
907 | // IWLIST need this flag to get TxPower | |
908 | // | |
909 | rrq->disabled = 0; | |
910 | } | |
911 | ||
912 | up(&ar->arSem); | |
913 | ||
914 | return ret; | |
915 | } | |
916 | ||
917 | /* | |
918 | * SIOCSIWRETRY | |
919 | * since iwconfig only provides us with one max retry value, we use it | |
920 | * to apply to data frames of the BE traffic class. | |
921 | */ | |
922 | static int | |
923 | ar6000_ioctl_siwretry(struct net_device *dev, | |
924 | struct iw_request_info *info, | |
925 | struct iw_param *rrq, char *extra) | |
926 | { | |
a71f0bf6 | 927 | struct ar6_softc *ar = (struct ar6_softc *)ar6k_priv(dev); |
30295c89 | 928 | |
4f69cef0 | 929 | if (is_iwioctl_allowed(ar->arNextMode, info->cmd) != 0) { |
30295c89 VM |
930 | A_PRINTF("wext_ioctl: cmd=0x%x not allowed in this mode\n", info->cmd); |
931 | return -EOPNOTSUPP; | |
932 | } | |
933 | ||
934 | if (ar->arWlanState == WLAN_DISABLED) { | |
935 | return -EIO; | |
936 | } | |
937 | ||
938 | if (rrq->disabled) { | |
939 | return -EOPNOTSUPP; | |
940 | } | |
941 | ||
942 | if ((rrq->flags & IW_RETRY_TYPE) != IW_RETRY_LIMIT) { | |
943 | return -EOPNOTSUPP; | |
944 | } | |
945 | ||
946 | if ( !(rrq->value >= WMI_MIN_RETRIES) || !(rrq->value <= WMI_MAX_RETRIES)) { | |
947 | return - EINVAL; | |
948 | } | |
1071a134 | 949 | if(ar->arWmiReady == true) |
30295c89 VM |
950 | { |
951 | if (wmi_set_retry_limits_cmd(ar->arWmi, DATA_FRAMETYPE, WMM_AC_BE, | |
4f69cef0 | 952 | rrq->value, 0) != 0){ |
30295c89 VM |
953 | return -EINVAL; |
954 | } | |
955 | } | |
956 | ar->arMaxRetries = rrq->value; | |
957 | return 0; | |
958 | } | |
959 | ||
960 | /* | |
961 | * SIOCGIWRETRY | |
962 | */ | |
963 | static int | |
964 | ar6000_ioctl_giwretry(struct net_device *dev, | |
965 | struct iw_request_info *info, | |
966 | struct iw_param *rrq, char *extra) | |
967 | { | |
a71f0bf6 | 968 | struct ar6_softc *ar = (struct ar6_softc *)ar6k_priv(dev); |
30295c89 | 969 | |
4f69cef0 | 970 | if (is_iwioctl_allowed(ar->arNextMode, info->cmd) != 0) { |
30295c89 VM |
971 | A_PRINTF("wext_ioctl: cmd=0x%x not allowed in this mode\n", info->cmd); |
972 | return -EOPNOTSUPP; | |
973 | } | |
974 | ||
975 | if (ar->arWlanState == WLAN_DISABLED) { | |
976 | return -EIO; | |
977 | } | |
978 | ||
979 | rrq->disabled = 0; | |
980 | switch (rrq->flags & IW_RETRY_TYPE) { | |
981 | case IW_RETRY_LIFETIME: | |
982 | return -EOPNOTSUPP; | |
983 | break; | |
984 | case IW_RETRY_LIMIT: | |
985 | rrq->flags = IW_RETRY_LIMIT; | |
986 | switch (rrq->flags & IW_RETRY_MODIFIER) { | |
987 | case IW_RETRY_MIN: | |
988 | rrq->flags |= IW_RETRY_MIN; | |
989 | rrq->value = WMI_MIN_RETRIES; | |
990 | break; | |
991 | case IW_RETRY_MAX: | |
992 | rrq->flags |= IW_RETRY_MAX; | |
993 | rrq->value = ar->arMaxRetries; | |
994 | break; | |
995 | } | |
996 | break; | |
997 | } | |
998 | return 0; | |
999 | } | |
1000 | ||
1001 | /* | |
1002 | * SIOCSIWENCODE | |
1003 | */ | |
1004 | static int | |
1005 | ar6000_ioctl_siwencode(struct net_device *dev, | |
1006 | struct iw_request_info *info, | |
1007 | struct iw_point *erq, char *keybuf) | |
1008 | { | |
a71f0bf6 | 1009 | struct ar6_softc *ar = (struct ar6_softc *)ar6k_priv(dev); |
30295c89 | 1010 | int index; |
f68057e6 | 1011 | s32 auth = 0; |
30295c89 | 1012 | |
4f69cef0 | 1013 | if (is_iwioctl_allowed(ar->arNextMode, info->cmd) != 0) { |
30295c89 VM |
1014 | A_PRINTF("wext_ioctl: cmd=0x%x not allowed in this mode\n", info->cmd); |
1015 | return -EOPNOTSUPP; | |
1016 | } | |
1017 | ||
1018 | if(ar->arNextMode != AP_NETWORK) { | |
1019 | /* | |
1020 | * Static WEP Keys should be configured before setting the SSID | |
1021 | */ | |
1022 | if (ar->arSsid[0] && erq->length) { | |
1023 | return -EIO; | |
1024 | } | |
1025 | } | |
1026 | ||
1027 | if (ar->arWlanState == WLAN_DISABLED) { | |
1028 | return -EIO; | |
1029 | } | |
1030 | ||
1031 | index = erq->flags & IW_ENCODE_INDEX; | |
1032 | ||
1033 | if (index && (((index - 1) < WMI_MIN_KEY_INDEX) || | |
1034 | ((index - 1) > WMI_MAX_KEY_INDEX))) | |
1035 | { | |
1036 | return -EIO; | |
1037 | } | |
1038 | ||
1039 | if (erq->flags & IW_ENCODE_DISABLED) { | |
1040 | /* | |
1041 | * Encryption disabled | |
1042 | */ | |
1043 | if (index) { | |
1044 | /* | |
1045 | * If key index was specified then clear the specified key | |
1046 | */ | |
1047 | index--; | |
1048 | A_MEMZERO(ar->arWepKeyList[index].arKey, | |
1049 | sizeof(ar->arWepKeyList[index].arKey)); | |
1050 | ar->arWepKeyList[index].arKeyLen = 0; | |
1051 | } | |
1052 | ar->arDot11AuthMode = OPEN_AUTH; | |
1053 | ar->arPairwiseCrypto = NONE_CRYPT; | |
1054 | ar->arGroupCrypto = NONE_CRYPT; | |
1055 | ar->arAuthMode = NONE_AUTH; | |
1056 | } else { | |
1057 | /* | |
1058 | * Enabling WEP encryption | |
1059 | */ | |
1060 | if (index) { | |
1061 | index--; /* keyindex is off base 1 in iwconfig */ | |
1062 | } | |
1063 | ||
1064 | if (erq->flags & IW_ENCODE_OPEN) { | |
1065 | auth |= OPEN_AUTH; | |
1066 | ar->arDefTxKeyIndex = index; | |
1067 | } | |
1068 | if (erq->flags & IW_ENCODE_RESTRICTED) { | |
1069 | auth |= SHARED_AUTH; | |
1070 | } | |
1071 | ||
1072 | if (!auth) { | |
1073 | auth = OPEN_AUTH; | |
1074 | } | |
1075 | ||
1076 | if (erq->length) { | |
1077 | if (!IEEE80211_IS_VALID_WEP_CIPHER_LEN(erq->length)) { | |
1078 | return -EIO; | |
1079 | } | |
1080 | ||
1081 | A_MEMZERO(ar->arWepKeyList[index].arKey, | |
1082 | sizeof(ar->arWepKeyList[index].arKey)); | |
05209262 | 1083 | memcpy(ar->arWepKeyList[index].arKey, keybuf, erq->length); |
30295c89 VM |
1084 | ar->arWepKeyList[index].arKeyLen = erq->length; |
1085 | ar->arDot11AuthMode = auth; | |
1086 | } else { | |
1087 | if (ar->arWepKeyList[index].arKeyLen == 0) { | |
1088 | return -EIO; | |
1089 | } | |
1090 | ar->arDefTxKeyIndex = index; | |
1091 | ||
1092 | if(ar->arSsidLen && ar->arWepKeyList[index].arKeyLen) { | |
1093 | wmi_addKey_cmd(ar->arWmi, | |
1094 | index, | |
1095 | WEP_CRYPT, | |
1096 | GROUP_USAGE | TX_USAGE, | |
1097 | ar->arWepKeyList[index].arKeyLen, | |
1098 | NULL, | |
1099 | ar->arWepKeyList[index].arKey, KEY_OP_INIT_VAL, NULL, | |
1100 | NO_SYNC_WMIFLAG); | |
1101 | } | |
1102 | } | |
1103 | ||
1104 | ar->arPairwiseCrypto = WEP_CRYPT; | |
1105 | ar->arGroupCrypto = WEP_CRYPT; | |
1106 | ar->arAuthMode = NONE_AUTH; | |
1107 | } | |
1108 | ||
1109 | if(ar->arNextMode != AP_NETWORK) { | |
1110 | /* | |
1111 | * profile has changed. Erase ssid to signal change | |
1112 | */ | |
1113 | A_MEMZERO(ar->arSsid, sizeof(ar->arSsid)); | |
1114 | ar->arSsidLen = 0; | |
1115 | } | |
1116 | ar->ap_profile_flag = 1; /* There is a change in profile */ | |
1117 | return 0; | |
1118 | } | |
1119 | ||
1120 | static int | |
1121 | ar6000_ioctl_giwencode(struct net_device *dev, | |
1122 | struct iw_request_info *info, | |
1123 | struct iw_point *erq, char *key) | |
1124 | { | |
a71f0bf6 | 1125 | struct ar6_softc *ar = (struct ar6_softc *)ar6k_priv(dev); |
ab3655da | 1126 | u8 keyIndex; |
30295c89 VM |
1127 | struct ar_wep_key *wk; |
1128 | ||
4f69cef0 | 1129 | if (is_iwioctl_allowed(ar->arNextMode, info->cmd) != 0) { |
30295c89 VM |
1130 | A_PRINTF("wext_ioctl: cmd=0x%x not allowed in this mode\n", info->cmd); |
1131 | return -EOPNOTSUPP; | |
1132 | } | |
1133 | ||
1134 | if (ar->arWlanState == WLAN_DISABLED) { | |
1135 | return -EIO; | |
1136 | } | |
1137 | ||
1138 | if (ar->arPairwiseCrypto == NONE_CRYPT) { | |
1139 | erq->length = 0; | |
1140 | erq->flags = IW_ENCODE_DISABLED; | |
1141 | } else { | |
1142 | if (ar->arPairwiseCrypto == WEP_CRYPT) { | |
1143 | /* get the keyIndex */ | |
1144 | keyIndex = erq->flags & IW_ENCODE_INDEX; | |
1145 | if (0 == keyIndex) { | |
1146 | keyIndex = ar->arDefTxKeyIndex; | |
1147 | } else if ((keyIndex - 1 < WMI_MIN_KEY_INDEX) || | |
1148 | (keyIndex - 1 > WMI_MAX_KEY_INDEX)) | |
1149 | { | |
1150 | keyIndex = WMI_MIN_KEY_INDEX; | |
1151 | } else { | |
1152 | keyIndex--; | |
1153 | } | |
1154 | erq->flags = keyIndex + 1; | |
1155 | erq->flags &= ~IW_ENCODE_DISABLED; | |
1156 | wk = &ar->arWepKeyList[keyIndex]; | |
1157 | if (erq->length > wk->arKeyLen) { | |
1158 | erq->length = wk->arKeyLen; | |
1159 | } | |
1160 | if (wk->arKeyLen) { | |
05209262 | 1161 | memcpy(key, wk->arKey, erq->length); |
30295c89 VM |
1162 | } |
1163 | } else { | |
1164 | erq->flags &= ~IW_ENCODE_DISABLED; | |
1165 | if (ar->user_saved_keys.keyOk) { | |
1166 | erq->length = ar->user_saved_keys.ucast_ik.ik_keylen; | |
1167 | if (erq->length) { | |
05209262 | 1168 | memcpy(key, ar->user_saved_keys.ucast_ik.ik_keydata, erq->length); |
30295c89 VM |
1169 | } |
1170 | } else { | |
1171 | erq->length = 1; // not really printing any key but let iwconfig know enc is on | |
1172 | } | |
1173 | } | |
1174 | ||
1175 | if (ar->arDot11AuthMode & OPEN_AUTH) { | |
1176 | erq->flags |= IW_ENCODE_OPEN; | |
1177 | } | |
1178 | if (ar->arDot11AuthMode & SHARED_AUTH) { | |
1179 | erq->flags |= IW_ENCODE_RESTRICTED; | |
1180 | } | |
1181 | } | |
1182 | ||
1183 | return 0; | |
1184 | } | |
1185 | ||
1186 | #if WIRELESS_EXT >= 18 | |
1187 | /* | |
1188 | * SIOCSIWGENIE | |
1189 | */ | |
1190 | static int | |
1191 | ar6000_ioctl_siwgenie(struct net_device *dev, | |
1192 | struct iw_request_info *info, | |
1193 | struct iw_point *erq, char *extra) | |
1194 | { | |
a71f0bf6 | 1195 | struct ar6_softc *ar = (struct ar6_softc *)ar6k_priv(dev); |
30295c89 VM |
1196 | |
1197 | #ifdef WAPI_ENABLE | |
ab3655da JP |
1198 | u8 *ie = erq->pointer; |
1199 | u8 ie_type = ie[0]; | |
4853ac05 | 1200 | u16 ie_length = erq->length; |
ab3655da | 1201 | u8 wapi_ie[128]; |
30295c89 VM |
1202 | #endif |
1203 | ||
1071a134 | 1204 | if (ar->arWmiReady == false) { |
30295c89 VM |
1205 | return -EIO; |
1206 | } | |
1207 | #ifdef WAPI_ENABLE | |
1208 | if (ie_type == IEEE80211_ELEMID_WAPI) { | |
1209 | if (ie_length > 0) { | |
1210 | if (copy_from_user(wapi_ie, ie, ie_length)) { | |
1211 | return -EIO; | |
1212 | } | |
1213 | } | |
1214 | wmi_set_appie_cmd(ar->arWmi, WMI_FRAME_ASSOC_REQ, ie_length, wapi_ie); | |
1215 | } else if (ie_length == 0) { | |
1216 | wmi_set_appie_cmd(ar->arWmi, WMI_FRAME_ASSOC_REQ, ie_length, wapi_ie); | |
1217 | } | |
1218 | #endif | |
1219 | return 0; | |
1220 | } | |
1221 | ||
1222 | ||
1223 | /* | |
1224 | * SIOCGIWGENIE | |
1225 | */ | |
1226 | static int | |
1227 | ar6000_ioctl_giwgenie(struct net_device *dev, | |
1228 | struct iw_request_info *info, | |
1229 | struct iw_point *erq, char *extra) | |
1230 | { | |
a71f0bf6 | 1231 | struct ar6_softc *ar = (struct ar6_softc *)ar6k_priv(dev); |
30295c89 | 1232 | |
1071a134 | 1233 | if (ar->arWmiReady == false) { |
30295c89 VM |
1234 | return -EIO; |
1235 | } | |
1236 | erq->length = 0; | |
1237 | erq->flags = 0; | |
1238 | ||
1239 | return 0; | |
1240 | } | |
1241 | ||
1242 | /* | |
1243 | * SIOCSIWAUTH | |
1244 | */ | |
1245 | static int | |
1246 | ar6000_ioctl_siwauth(struct net_device *dev, | |
1247 | struct iw_request_info *info, | |
1248 | struct iw_param *data, char *extra) | |
1249 | { | |
a71f0bf6 | 1250 | struct ar6_softc *ar = (struct ar6_softc *)ar6k_priv(dev); |
30295c89 | 1251 | |
1071a134 | 1252 | bool profChanged; |
4853ac05 | 1253 | u16 param; |
f68057e6 JP |
1254 | s32 ret; |
1255 | s32 value; | |
30295c89 | 1256 | |
1071a134 | 1257 | if (ar->arWmiReady == false) { |
30295c89 VM |
1258 | return -EIO; |
1259 | } | |
1260 | ||
1261 | if (ar->arWlanState == WLAN_DISABLED) { | |
1262 | return -EIO; | |
1263 | } | |
1264 | ||
1265 | param = data->flags & IW_AUTH_INDEX; | |
1266 | value = data->value; | |
1071a134 | 1267 | profChanged = true; |
30295c89 VM |
1268 | ret = 0; |
1269 | ||
1270 | switch (param) { | |
1271 | case IW_AUTH_WPA_VERSION: | |
1272 | if (value & IW_AUTH_WPA_VERSION_DISABLED) { | |
1273 | ar->arAuthMode = NONE_AUTH; | |
1274 | } else if (value & IW_AUTH_WPA_VERSION_WPA) { | |
1275 | ar->arAuthMode = WPA_AUTH; | |
1276 | } else if (value & IW_AUTH_WPA_VERSION_WPA2) { | |
1277 | ar->arAuthMode = WPA2_AUTH; | |
1278 | } else { | |
1279 | ret = -1; | |
1071a134 | 1280 | profChanged = false; |
30295c89 VM |
1281 | } |
1282 | break; | |
1283 | case IW_AUTH_CIPHER_PAIRWISE: | |
1284 | if (value & IW_AUTH_CIPHER_NONE) { | |
1285 | ar->arPairwiseCrypto = NONE_CRYPT; | |
1286 | ar->arPairwiseCryptoLen = 0; | |
1287 | } else if (value & IW_AUTH_CIPHER_WEP40) { | |
1288 | ar->arPairwiseCrypto = WEP_CRYPT; | |
1289 | ar->arPairwiseCryptoLen = 5; | |
1290 | } else if (value & IW_AUTH_CIPHER_TKIP) { | |
1291 | ar->arPairwiseCrypto = TKIP_CRYPT; | |
1292 | ar->arPairwiseCryptoLen = 0; | |
1293 | } else if (value & IW_AUTH_CIPHER_CCMP) { | |
1294 | ar->arPairwiseCrypto = AES_CRYPT; | |
1295 | ar->arPairwiseCryptoLen = 0; | |
1296 | } else if (value & IW_AUTH_CIPHER_WEP104) { | |
1297 | ar->arPairwiseCrypto = WEP_CRYPT; | |
1298 | ar->arPairwiseCryptoLen = 13; | |
1299 | } else { | |
1300 | ret = -1; | |
1071a134 | 1301 | profChanged = false; |
30295c89 VM |
1302 | } |
1303 | break; | |
1304 | case IW_AUTH_CIPHER_GROUP: | |
1305 | if (value & IW_AUTH_CIPHER_NONE) { | |
1306 | ar->arGroupCrypto = NONE_CRYPT; | |
1307 | ar->arGroupCryptoLen = 0; | |
1308 | } else if (value & IW_AUTH_CIPHER_WEP40) { | |
1309 | ar->arGroupCrypto = WEP_CRYPT; | |
1310 | ar->arGroupCryptoLen = 5; | |
1311 | } else if (value & IW_AUTH_CIPHER_TKIP) { | |
1312 | ar->arGroupCrypto = TKIP_CRYPT; | |
1313 | ar->arGroupCryptoLen = 0; | |
1314 | } else if (value & IW_AUTH_CIPHER_CCMP) { | |
1315 | ar->arGroupCrypto = AES_CRYPT; | |
1316 | ar->arGroupCryptoLen = 0; | |
1317 | } else if (value & IW_AUTH_CIPHER_WEP104) { | |
1318 | ar->arGroupCrypto = WEP_CRYPT; | |
1319 | ar->arGroupCryptoLen = 13; | |
1320 | } else { | |
1321 | ret = -1; | |
1071a134 | 1322 | profChanged = false; |
30295c89 VM |
1323 | } |
1324 | break; | |
1325 | case IW_AUTH_KEY_MGMT: | |
1326 | if (value & IW_AUTH_KEY_MGMT_PSK) { | |
1327 | if (WPA_AUTH == ar->arAuthMode) { | |
1328 | ar->arAuthMode = WPA_PSK_AUTH; | |
1329 | } else if (WPA2_AUTH == ar->arAuthMode) { | |
1330 | ar->arAuthMode = WPA2_PSK_AUTH; | |
1331 | } else { | |
1332 | ret = -1; | |
1333 | } | |
1334 | } else if (!(value & IW_AUTH_KEY_MGMT_802_1X)) { | |
1335 | ar->arAuthMode = NONE_AUTH; | |
1336 | } | |
1337 | break; | |
1338 | case IW_AUTH_TKIP_COUNTERMEASURES: | |
1339 | wmi_set_tkip_countermeasures_cmd(ar->arWmi, value); | |
1071a134 | 1340 | profChanged = false; |
30295c89 VM |
1341 | break; |
1342 | case IW_AUTH_DROP_UNENCRYPTED: | |
1071a134 | 1343 | profChanged = false; |
30295c89 VM |
1344 | break; |
1345 | case IW_AUTH_80211_AUTH_ALG: | |
1346 | ar->arDot11AuthMode = 0; | |
1347 | if (value & IW_AUTH_ALG_OPEN_SYSTEM) { | |
1348 | ar->arDot11AuthMode |= OPEN_AUTH; | |
1349 | } | |
1350 | if (value & IW_AUTH_ALG_SHARED_KEY) { | |
1351 | ar->arDot11AuthMode |= SHARED_AUTH; | |
1352 | } | |
1353 | if (value & IW_AUTH_ALG_LEAP) { | |
1354 | ar->arDot11AuthMode = LEAP_AUTH; | |
1355 | } | |
1356 | if(ar->arDot11AuthMode == 0) { | |
1357 | ret = -1; | |
1071a134 | 1358 | profChanged = false; |
30295c89 VM |
1359 | } |
1360 | break; | |
1361 | case IW_AUTH_WPA_ENABLED: | |
1362 | if (!value) { | |
1363 | ar->arAuthMode = NONE_AUTH; | |
1364 | /* when the supplicant is stopped, it calls this | |
1365 | * handler with value=0. The followings need to be | |
1366 | * reset if the STA were to connect again | |
1367 | * without security | |
1368 | */ | |
1369 | ar->arDot11AuthMode = OPEN_AUTH; | |
1370 | ar->arPairwiseCrypto = NONE_CRYPT; | |
1371 | ar->arPairwiseCryptoLen = 0; | |
1372 | ar->arGroupCrypto = NONE_CRYPT; | |
1373 | ar->arGroupCryptoLen = 0; | |
1374 | } | |
1375 | break; | |
1376 | case IW_AUTH_RX_UNENCRYPTED_EAPOL: | |
1071a134 | 1377 | profChanged = false; |
30295c89 VM |
1378 | break; |
1379 | case IW_AUTH_ROAMING_CONTROL: | |
1071a134 | 1380 | profChanged = false; |
30295c89 VM |
1381 | break; |
1382 | case IW_AUTH_PRIVACY_INVOKED: | |
1383 | if (!value) { | |
1384 | ar->arPairwiseCrypto = NONE_CRYPT; | |
1385 | ar->arPairwiseCryptoLen = 0; | |
1386 | ar->arGroupCrypto = NONE_CRYPT; | |
1387 | ar->arGroupCryptoLen = 0; | |
1388 | } | |
1389 | break; | |
1390 | #ifdef WAPI_ENABLE | |
1391 | case IW_AUTH_WAPI_ENABLED: | |
1392 | ar->arWapiEnable = value; | |
1393 | break; | |
1394 | #endif | |
1395 | default: | |
1396 | ret = -1; | |
1071a134 | 1397 | profChanged = false; |
30295c89 VM |
1398 | break; |
1399 | } | |
1400 | ||
1071a134 | 1401 | if (profChanged == true) { |
30295c89 VM |
1402 | /* |
1403 | * profile has changed. Erase ssid to signal change | |
1404 | */ | |
1405 | A_MEMZERO(ar->arSsid, sizeof(ar->arSsid)); | |
1406 | ar->arSsidLen = 0; | |
1407 | } | |
1408 | ||
1409 | return ret; | |
1410 | } | |
1411 | ||
1412 | ||
1413 | /* | |
1414 | * SIOCGIWAUTH | |
1415 | */ | |
1416 | static int | |
1417 | ar6000_ioctl_giwauth(struct net_device *dev, | |
1418 | struct iw_request_info *info, | |
1419 | struct iw_param *data, char *extra) | |
1420 | { | |
a71f0bf6 | 1421 | struct ar6_softc *ar = (struct ar6_softc *)ar6k_priv(dev); |
4853ac05 | 1422 | u16 param; |
f68057e6 | 1423 | s32 ret; |
30295c89 | 1424 | |
1071a134 | 1425 | if (ar->arWmiReady == false) { |
30295c89 VM |
1426 | return -EIO; |
1427 | } | |
1428 | ||
1429 | if (ar->arWlanState == WLAN_DISABLED) { | |
1430 | return -EIO; | |
1431 | } | |
1432 | ||
1433 | param = data->flags & IW_AUTH_INDEX; | |
1434 | ret = 0; | |
1435 | data->value = 0; | |
1436 | ||
1437 | ||
1438 | switch (param) { | |
1439 | case IW_AUTH_WPA_VERSION: | |
1440 | if (ar->arAuthMode == NONE_AUTH) { | |
1441 | data->value |= IW_AUTH_WPA_VERSION_DISABLED; | |
1442 | } else if (ar->arAuthMode == WPA_AUTH) { | |
1443 | data->value |= IW_AUTH_WPA_VERSION_WPA; | |
1444 | } else if (ar->arAuthMode == WPA2_AUTH) { | |
1445 | data->value |= IW_AUTH_WPA_VERSION_WPA2; | |
1446 | } else { | |
1447 | ret = -1; | |
1448 | } | |
1449 | break; | |
1450 | case IW_AUTH_CIPHER_PAIRWISE: | |
1451 | if (ar->arPairwiseCrypto == NONE_CRYPT) { | |
1452 | data->value |= IW_AUTH_CIPHER_NONE; | |
1453 | } else if (ar->arPairwiseCrypto == WEP_CRYPT) { | |
1454 | if (ar->arPairwiseCryptoLen == 13) { | |
1455 | data->value |= IW_AUTH_CIPHER_WEP104; | |
1456 | } else { | |
1457 | data->value |= IW_AUTH_CIPHER_WEP40; | |
1458 | } | |
1459 | } else if (ar->arPairwiseCrypto == TKIP_CRYPT) { | |
1460 | data->value |= IW_AUTH_CIPHER_TKIP; | |
1461 | } else if (ar->arPairwiseCrypto == AES_CRYPT) { | |
1462 | data->value |= IW_AUTH_CIPHER_CCMP; | |
1463 | } else { | |
1464 | ret = -1; | |
1465 | } | |
1466 | break; | |
1467 | case IW_AUTH_CIPHER_GROUP: | |
1468 | if (ar->arGroupCrypto == NONE_CRYPT) { | |
1469 | data->value |= IW_AUTH_CIPHER_NONE; | |
1470 | } else if (ar->arGroupCrypto == WEP_CRYPT) { | |
1471 | if (ar->arGroupCryptoLen == 13) { | |
1472 | data->value |= IW_AUTH_CIPHER_WEP104; | |
1473 | } else { | |
1474 | data->value |= IW_AUTH_CIPHER_WEP40; | |
1475 | } | |
1476 | } else if (ar->arGroupCrypto == TKIP_CRYPT) { | |
1477 | data->value |= IW_AUTH_CIPHER_TKIP; | |
1478 | } else if (ar->arGroupCrypto == AES_CRYPT) { | |
1479 | data->value |= IW_AUTH_CIPHER_CCMP; | |
1480 | } else { | |
1481 | ret = -1; | |
1482 | } | |
1483 | break; | |
1484 | case IW_AUTH_KEY_MGMT: | |
1485 | if ((ar->arAuthMode == WPA_PSK_AUTH) || | |
1486 | (ar->arAuthMode == WPA2_PSK_AUTH)) { | |
1487 | data->value |= IW_AUTH_KEY_MGMT_PSK; | |
1488 | } else if ((ar->arAuthMode == WPA_AUTH) || | |
1489 | (ar->arAuthMode == WPA2_AUTH)) { | |
1490 | data->value |= IW_AUTH_KEY_MGMT_802_1X; | |
1491 | } | |
1492 | break; | |
1493 | case IW_AUTH_TKIP_COUNTERMEASURES: | |
1494 | // TODO. Save countermeassure enable/disable | |
1495 | data->value = 0; | |
1496 | break; | |
1497 | case IW_AUTH_DROP_UNENCRYPTED: | |
1498 | break; | |
1499 | case IW_AUTH_80211_AUTH_ALG: | |
1500 | if (ar->arDot11AuthMode == OPEN_AUTH) { | |
1501 | data->value |= IW_AUTH_ALG_OPEN_SYSTEM; | |
1502 | } else if (ar->arDot11AuthMode == SHARED_AUTH) { | |
1503 | data->value |= IW_AUTH_ALG_SHARED_KEY; | |
1504 | } else if (ar->arDot11AuthMode == LEAP_AUTH) { | |
1505 | data->value |= IW_AUTH_ALG_LEAP; | |
1506 | } else { | |
1507 | ret = -1; | |
1508 | } | |
1509 | break; | |
1510 | case IW_AUTH_WPA_ENABLED: | |
1511 | if (ar->arAuthMode == NONE_AUTH) { | |
1512 | data->value = 0; | |
1513 | } else { | |
1514 | data->value = 1; | |
1515 | } | |
1516 | break; | |
1517 | case IW_AUTH_RX_UNENCRYPTED_EAPOL: | |
1518 | break; | |
1519 | case IW_AUTH_ROAMING_CONTROL: | |
1520 | break; | |
1521 | case IW_AUTH_PRIVACY_INVOKED: | |
1522 | if (ar->arPairwiseCrypto == NONE_CRYPT) { | |
1523 | data->value = 0; | |
1524 | } else { | |
1525 | data->value = 1; | |
1526 | } | |
1527 | break; | |
1528 | #ifdef WAPI_ENABLE | |
1529 | case IW_AUTH_WAPI_ENABLED: | |
1530 | data->value = ar->arWapiEnable; | |
1531 | break; | |
1532 | #endif | |
1533 | default: | |
1534 | ret = -1; | |
1535 | break; | |
1536 | } | |
1537 | ||
1538 | return 0; | |
1539 | } | |
1540 | ||
1541 | /* | |
1542 | * SIOCSIWPMKSA | |
1543 | */ | |
1544 | static int | |
1545 | ar6000_ioctl_siwpmksa(struct net_device *dev, | |
1546 | struct iw_request_info *info, | |
1547 | struct iw_point *data, char *extra) | |
1548 | { | |
a71f0bf6 | 1549 | struct ar6_softc *ar = (struct ar6_softc *)ar6k_priv(dev); |
f68057e6 | 1550 | s32 ret; |
1f4c34bd | 1551 | int status; |
30295c89 VM |
1552 | struct iw_pmksa *pmksa; |
1553 | ||
1554 | pmksa = (struct iw_pmksa *)extra; | |
1555 | ||
1071a134 | 1556 | if (ar->arWmiReady == false) { |
30295c89 VM |
1557 | return -EIO; |
1558 | } | |
1559 | ||
1560 | ret = 0; | |
4f69cef0 | 1561 | status = 0; |
30295c89 VM |
1562 | |
1563 | switch (pmksa->cmd) { | |
1564 | case IW_PMKSA_ADD: | |
ab3655da | 1565 | status = wmi_setPmkid_cmd(ar->arWmi, (u8 *)pmksa->bssid.sa_data, pmksa->pmkid, true); |
30295c89 VM |
1566 | break; |
1567 | case IW_PMKSA_REMOVE: | |
ab3655da | 1568 | status = wmi_setPmkid_cmd(ar->arWmi, (u8 *)pmksa->bssid.sa_data, pmksa->pmkid, false); |
30295c89 VM |
1569 | break; |
1570 | case IW_PMKSA_FLUSH: | |
1071a134 | 1571 | if (ar->arConnected == true) { |
30295c89 VM |
1572 | status = wmi_setPmkid_cmd(ar->arWmi, ar->arBssid, NULL, 0); |
1573 | } | |
1574 | break; | |
1575 | default: | |
1576 | ret=-1; | |
1577 | break; | |
1578 | } | |
a1d46529 | 1579 | if (status) { |
30295c89 VM |
1580 | ret = -1; |
1581 | } | |
1582 | ||
1583 | return ret; | |
1584 | } | |
1585 | ||
1586 | #ifdef WAPI_ENABLE | |
1587 | ||
1588 | #define PN_INIT 0x5c365c36 | |
1589 | ||
1590 | static int ar6000_set_wapi_key(struct net_device *dev, | |
1591 | struct iw_request_info *info, | |
1592 | struct iw_point *erq, char *extra) | |
1593 | { | |
a71f0bf6 | 1594 | struct ar6_softc *ar = (struct ar6_softc *)ar6k_priv(dev); |
30295c89 VM |
1595 | struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; |
1596 | KEY_USAGE keyUsage = 0; | |
f68057e6 | 1597 | s32 keyLen; |
ab3655da | 1598 | u8 *keyData; |
f68057e6 | 1599 | s32 index; |
e1ce2a3a | 1600 | u32 *PN; |
f68057e6 | 1601 | s32 i; |
1f4c34bd | 1602 | int status; |
ab3655da | 1603 | u8 wapiKeyRsc[16]; |
30295c89 | 1604 | CRYPTO_TYPE keyType = WAPI_CRYPT; |
ab3655da | 1605 | const u8 broadcastMac[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; |
30295c89 VM |
1606 | |
1607 | index = erq->flags & IW_ENCODE_INDEX; | |
1608 | if (index && (((index - 1) < WMI_MIN_KEY_INDEX) || | |
1609 | ((index - 1) > WMI_MAX_KEY_INDEX))) { | |
1610 | return -EIO; | |
1611 | } | |
1612 | ||
1613 | index--; | |
1614 | if (index < 0 || index > 4) { | |
1615 | return -EIO; | |
1616 | } | |
ab3655da | 1617 | keyData = (u8 *)(ext + 1); |
30295c89 | 1618 | keyLen = erq->length - sizeof(struct iw_encode_ext); |
05209262 | 1619 | memcpy(wapiKeyRsc, ext->tx_seq, sizeof(wapiKeyRsc)); |
30295c89 | 1620 | |
395e1cae | 1621 | if (memcmp(ext->addr.sa_data, broadcastMac, sizeof(broadcastMac)) == 0) { |
30295c89 | 1622 | keyUsage |= GROUP_USAGE; |
e1ce2a3a | 1623 | PN = (u32 *)wapiKeyRsc; |
30295c89 VM |
1624 | for (i = 0; i < 4; i++) { |
1625 | PN[i] = PN_INIT; | |
1626 | } | |
1627 | } else { | |
1628 | keyUsage |= PAIRWISE_USAGE; | |
1629 | } | |
1630 | status = wmi_addKey_cmd(ar->arWmi, | |
1631 | index, | |
1632 | keyType, | |
1633 | keyUsage, | |
1634 | keyLen, | |
1635 | wapiKeyRsc, | |
1636 | keyData, | |
1637 | KEY_OP_INIT_WAPIPN, | |
1638 | NULL, | |
1639 | SYNC_BEFORE_WMIFLAG); | |
4f69cef0 | 1640 | if (0 != status) { |
30295c89 VM |
1641 | return -EIO; |
1642 | } | |
1643 | return 0; | |
1644 | } | |
1645 | ||
1646 | #endif | |
1647 | ||
1648 | /* | |
1649 | * SIOCSIWENCODEEXT | |
1650 | */ | |
1651 | static int | |
1652 | ar6000_ioctl_siwencodeext(struct net_device *dev, | |
1653 | struct iw_request_info *info, | |
1654 | struct iw_point *erq, char *extra) | |
1655 | { | |
a71f0bf6 | 1656 | struct ar6_softc *ar = (struct ar6_softc *)ar6k_priv(dev); |
f68057e6 | 1657 | s32 index; |
30295c89 VM |
1658 | struct iw_encode_ext *ext; |
1659 | KEY_USAGE keyUsage; | |
f68057e6 | 1660 | s32 keyLen; |
ab3655da JP |
1661 | u8 *keyData; |
1662 | u8 keyRsc[8]; | |
1f4c34bd | 1663 | int status; |
30295c89 VM |
1664 | CRYPTO_TYPE keyType; |
1665 | #ifdef USER_KEYS | |
1666 | struct ieee80211req_key ik; | |
1667 | #endif /* USER_KEYS */ | |
1668 | ||
1669 | if (ar->arWlanState == WLAN_DISABLED) { | |
1670 | return -EIO; | |
1671 | } | |
1672 | ||
1673 | #ifdef USER_KEYS | |
1071a134 | 1674 | ar->user_saved_keys.keyOk = false; |
30295c89 VM |
1675 | #endif /* USER_KEYS */ |
1676 | ||
1677 | index = erq->flags & IW_ENCODE_INDEX; | |
1678 | ||
1679 | if (index && (((index - 1) < WMI_MIN_KEY_INDEX) || | |
1680 | ((index - 1) > WMI_MAX_KEY_INDEX))) | |
1681 | { | |
1682 | return -EIO; | |
1683 | } | |
1684 | ||
1685 | ext = (struct iw_encode_ext *)extra; | |
1686 | if (erq->flags & IW_ENCODE_DISABLED) { | |
1687 | /* | |
1688 | * Encryption disabled | |
1689 | */ | |
1690 | if (index) { | |
1691 | /* | |
1692 | * If key index was specified then clear the specified key | |
1693 | */ | |
1694 | index--; | |
1695 | A_MEMZERO(ar->arWepKeyList[index].arKey, | |
1696 | sizeof(ar->arWepKeyList[index].arKey)); | |
1697 | ar->arWepKeyList[index].arKeyLen = 0; | |
1698 | } | |
1699 | } else { | |
1700 | /* | |
1701 | * Enabling WEP encryption | |
1702 | */ | |
1703 | if (index) { | |
1704 | index--; /* keyindex is off base 1 in iwconfig */ | |
1705 | } | |
1706 | ||
1707 | keyUsage = 0; | |
1708 | keyLen = erq->length - sizeof(struct iw_encode_ext); | |
1709 | ||
1710 | if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { | |
1711 | keyUsage = TX_USAGE; | |
1712 | ar->arDefTxKeyIndex = index; | |
1713 | // Just setting the key index | |
1714 | if (keyLen == 0) { | |
1715 | return 0; | |
1716 | } | |
1717 | } | |
1718 | ||
1719 | if (keyLen <= 0) { | |
1720 | return -EIO; | |
1721 | } | |
1722 | ||
1723 | /* key follows iw_encode_ext */ | |
ab3655da | 1724 | keyData = (u8 *)(ext + 1); |
30295c89 VM |
1725 | |
1726 | switch (ext->alg) { | |
1727 | case IW_ENCODE_ALG_WEP: | |
1728 | keyType = WEP_CRYPT; | |
1729 | #ifdef USER_KEYS | |
1730 | ik.ik_type = IEEE80211_CIPHER_WEP; | |
1731 | #endif /* USER_KEYS */ | |
1732 | if (!IEEE80211_IS_VALID_WEP_CIPHER_LEN(keyLen)) { | |
1733 | return -EIO; | |
1734 | } | |
1735 | ||
1736 | /* Check whether it is static wep. */ | |
1737 | if (!ar->arConnected) { | |
1738 | A_MEMZERO(ar->arWepKeyList[index].arKey, | |
1739 | sizeof(ar->arWepKeyList[index].arKey)); | |
05209262 | 1740 | memcpy(ar->arWepKeyList[index].arKey, keyData, keyLen); |
30295c89 VM |
1741 | ar->arWepKeyList[index].arKeyLen = keyLen; |
1742 | ||
1743 | return 0; | |
1744 | } | |
1745 | break; | |
1746 | case IW_ENCODE_ALG_TKIP: | |
1747 | keyType = TKIP_CRYPT; | |
1748 | #ifdef USER_KEYS | |
1749 | ik.ik_type = IEEE80211_CIPHER_TKIP; | |
1750 | #endif /* USER_KEYS */ | |
1751 | break; | |
1752 | case IW_ENCODE_ALG_CCMP: | |
1753 | keyType = AES_CRYPT; | |
1754 | #ifdef USER_KEYS | |
1755 | ik.ik_type = IEEE80211_CIPHER_AES_CCM; | |
1756 | #endif /* USER_KEYS */ | |
1757 | break; | |
1758 | #ifdef WAPI_ENABLE | |
1759 | case IW_ENCODE_ALG_SM4: | |
1760 | if (ar->arWapiEnable) { | |
1761 | return ar6000_set_wapi_key(dev, info, erq, extra); | |
1762 | } else { | |
1763 | return -EIO; | |
1764 | } | |
1765 | #endif | |
1766 | case IW_ENCODE_ALG_PMK: | |
1767 | ar->arConnectCtrlFlags |= CONNECT_DO_WPA_OFFLOAD; | |
1768 | return wmi_set_pmk_cmd(ar->arWmi, keyData); | |
1769 | default: | |
1770 | return -EIO; | |
1771 | } | |
1772 | ||
1773 | ||
1774 | if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) { | |
1775 | keyUsage |= GROUP_USAGE; | |
1776 | } else { | |
1777 | keyUsage |= PAIRWISE_USAGE; | |
1778 | } | |
1779 | ||
1780 | if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) { | |
05209262 | 1781 | memcpy(keyRsc, ext->rx_seq, sizeof(keyRsc)); |
30295c89 VM |
1782 | } else { |
1783 | A_MEMZERO(keyRsc, sizeof(keyRsc)); | |
1784 | } | |
1785 | ||
1786 | if (((WPA_PSK_AUTH == ar->arAuthMode) || (WPA2_PSK_AUTH == ar->arAuthMode)) && | |
1787 | (GROUP_USAGE & keyUsage)) | |
1788 | { | |
1789 | A_UNTIMEOUT(&ar->disconnect_timer); | |
1790 | } | |
1791 | ||
1792 | status = wmi_addKey_cmd(ar->arWmi, index, keyType, keyUsage, | |
1793 | keyLen, keyRsc, | |
1794 | keyData, KEY_OP_INIT_VAL, | |
ab3655da | 1795 | (u8 *)ext->addr.sa_data, |
30295c89 | 1796 | SYNC_BOTH_WMIFLAG); |
a1d46529 | 1797 | if (status) { |
30295c89 VM |
1798 | return -EIO; |
1799 | } | |
1800 | ||
1801 | #ifdef USER_KEYS | |
1802 | ik.ik_keyix = index; | |
1803 | ik.ik_keylen = keyLen; | |
1804 | memcpy(ik.ik_keydata, keyData, keyLen); | |
1805 | memcpy(&ik.ik_keyrsc, keyRsc, sizeof(keyRsc)); | |
1806 | memcpy(ik.ik_macaddr, ext->addr.sa_data, ETH_ALEN); | |
1807 | if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) { | |
1808 | memcpy(&ar->user_saved_keys.bcast_ik, &ik, | |
1809 | sizeof(struct ieee80211req_key)); | |
1810 | } else { | |
1811 | memcpy(&ar->user_saved_keys.ucast_ik, &ik, | |
1812 | sizeof(struct ieee80211req_key)); | |
1813 | } | |
1071a134 | 1814 | ar->user_saved_keys.keyOk = true; |
30295c89 VM |
1815 | #endif /* USER_KEYS */ |
1816 | } | |
1817 | ||
1818 | ||
1819 | return 0; | |
1820 | } | |
1821 | ||
1822 | /* | |
1823 | * SIOCGIWENCODEEXT | |
1824 | */ | |
1825 | static int | |
1826 | ar6000_ioctl_giwencodeext(struct net_device *dev, | |
1827 | struct iw_request_info *info, | |
1828 | struct iw_point *erq, char *extra) | |
1829 | { | |
a71f0bf6 | 1830 | struct ar6_softc *ar = (struct ar6_softc *)ar6k_priv(dev); |
30295c89 VM |
1831 | |
1832 | if (ar->arWlanState == WLAN_DISABLED) { | |
1833 | return -EIO; | |
1834 | } | |
1835 | ||
1836 | if (ar->arPairwiseCrypto == NONE_CRYPT) { | |
1837 | erq->length = 0; | |
1838 | erq->flags = IW_ENCODE_DISABLED; | |
1839 | } else { | |
1840 | erq->length = 0; | |
1841 | } | |
1842 | ||
1843 | return 0; | |
1844 | } | |
1845 | #endif // WIRELESS_EXT >= 18 | |
1846 | ||
1847 | #if WIRELESS_EXT > 20 | |
1848 | static int ar6000_ioctl_siwpower(struct net_device *dev, | |
1849 | struct iw_request_info *info, | |
1850 | union iwreq_data *wrqu, char *extra) | |
1851 | { | |
1852 | #ifndef ATH6K_CONFIG_OTA_MODE | |
a71f0bf6 | 1853 | struct ar6_softc *ar = (struct ar6_softc *)ar6k_priv(dev); |
30295c89 VM |
1854 | WMI_POWER_MODE power_mode; |
1855 | ||
1071a134 | 1856 | if (ar->arWmiReady == false) { |
30295c89 VM |
1857 | return -EIO; |
1858 | } | |
1859 | ||
1860 | if (ar->arWlanState == WLAN_DISABLED) { | |
1861 | return -EIO; | |
1862 | } | |
1863 | ||
1864 | if (wrqu->power.disabled) | |
1865 | power_mode = MAX_PERF_POWER; | |
1866 | else | |
1867 | power_mode = REC_POWER; | |
1868 | ||
1869 | if (wmi_powermode_cmd(ar->arWmi, power_mode) < 0) | |
1870 | return -EIO; | |
1871 | #endif | |
1872 | return 0; | |
1873 | } | |
1874 | ||
1875 | static int ar6000_ioctl_giwpower(struct net_device *dev, | |
1876 | struct iw_request_info *info, | |
1877 | union iwreq_data *wrqu, char *extra) | |
1878 | { | |
a71f0bf6 | 1879 | struct ar6_softc *ar = (struct ar6_softc *)ar6k_priv(dev); |
30295c89 VM |
1880 | WMI_POWER_MODE power_mode; |
1881 | ||
1071a134 | 1882 | if (ar->arWmiReady == false) { |
30295c89 VM |
1883 | return -EIO; |
1884 | } | |
1885 | ||
1886 | if (ar->arWlanState == WLAN_DISABLED) { | |
1887 | return -EIO; | |
1888 | } | |
1889 | ||
1890 | power_mode = wmi_get_power_mode_cmd(ar->arWmi); | |
1891 | ||
1892 | if (power_mode == MAX_PERF_POWER) | |
1893 | wrqu->power.disabled = 1; | |
1894 | else | |
1895 | wrqu->power.disabled = 0; | |
1896 | ||
1897 | return 0; | |
1898 | } | |
1899 | #endif // WIRELESS_EXT > 20 | |
1900 | ||
1901 | /* | |
1902 | * SIOCGIWNAME | |
1903 | */ | |
1904 | int | |
1905 | ar6000_ioctl_giwname(struct net_device *dev, | |
1906 | struct iw_request_info *info, | |
1907 | char *name, char *extra) | |
1908 | { | |
ab3655da | 1909 | u8 capability; |
a71f0bf6 | 1910 | struct ar6_softc *ar = (struct ar6_softc *)ar6k_priv(dev); |
30295c89 | 1911 | |
4f69cef0 | 1912 | if (is_iwioctl_allowed(ar->arNextMode, info->cmd) != 0) { |
30295c89 VM |
1913 | A_PRINTF("wext_ioctl: cmd=0x%x not allowed in this mode\n", info->cmd); |
1914 | return -EOPNOTSUPP; | |
1915 | } | |
1916 | ||
1917 | if (ar->arWlanState == WLAN_DISABLED) { | |
1918 | return -EIO; | |
1919 | } | |
1920 | ||
1921 | capability = ar->arPhyCapability; | |
1922 | if(ar->arNetworkType == INFRA_NETWORK && ar->arConnected) { | |
1923 | bss_t *bss = wmi_find_node(ar->arWmi, ar->arBssid); | |
1924 | if (bss) { | |
1925 | capability = get_bss_phy_capability(bss); | |
1926 | wmi_node_return(ar->arWmi, bss); | |
1927 | } | |
1928 | } | |
1929 | switch (capability) { | |
1930 | case (WMI_11A_CAPABILITY): | |
1931 | strncpy(name, "AR6000 802.11a", IFNAMSIZ); | |
1932 | break; | |
1933 | case (WMI_11G_CAPABILITY): | |
1934 | strncpy(name, "AR6000 802.11g", IFNAMSIZ); | |
1935 | break; | |
1936 | case (WMI_11AG_CAPABILITY): | |
1937 | strncpy(name, "AR6000 802.11ag", IFNAMSIZ); | |
1938 | break; | |
1939 | case (WMI_11NA_CAPABILITY): | |
1940 | strncpy(name, "AR6000 802.11na", IFNAMSIZ); | |
1941 | break; | |
1942 | case (WMI_11NG_CAPABILITY): | |
1943 | strncpy(name, "AR6000 802.11ng", IFNAMSIZ); | |
1944 | break; | |
1945 | case (WMI_11NAG_CAPABILITY): | |
1946 | strncpy(name, "AR6000 802.11nag", IFNAMSIZ); | |
1947 | break; | |
1948 | default: | |
1949 | strncpy(name, "AR6000 802.11b", IFNAMSIZ); | |
1950 | break; | |
1951 | } | |
1952 | ||
1953 | return 0; | |
1954 | } | |
1955 | ||
1956 | /* | |
1957 | * SIOCSIWFREQ | |
1958 | */ | |
1959 | int | |
1960 | ar6000_ioctl_siwfreq(struct net_device *dev, | |
1961 | struct iw_request_info *info, | |
1962 | struct iw_freq *freq, char *extra) | |
1963 | { | |
a71f0bf6 | 1964 | struct ar6_softc *ar = (struct ar6_softc *)ar6k_priv(dev); |
30295c89 | 1965 | |
4f69cef0 | 1966 | if (is_iwioctl_allowed(ar->arNextMode, info->cmd) != 0) { |
30295c89 VM |
1967 | A_PRINTF("wext_ioctl: cmd=0x%x not allowed in this mode\n", info->cmd); |
1968 | return -EOPNOTSUPP; | |
1969 | } | |
1970 | ||
1971 | if (ar->arWlanState == WLAN_DISABLED) { | |
1972 | return -EIO; | |
1973 | } | |
1974 | ||
1975 | /* | |
1976 | * We support limiting the channels via wmiconfig. | |
1977 | * | |
1978 | * We use this command to configure the channel hint for the connect cmd | |
1979 | * so it is possible the target will end up connecting to a different | |
1980 | * channel. | |
1981 | */ | |
1982 | if (freq->e > 1) { | |
1983 | return -EINVAL; | |
1984 | } else if (freq->e == 1) { | |
1985 | ar->arChannelHint = freq->m / 100000; | |
1986 | } else { | |
1987 | if(freq->m) { | |
1988 | ar->arChannelHint = wlan_ieee2freq(freq->m); | |
1989 | } else { | |
1990 | /* Auto Channel Selection */ | |
1991 | ar->arChannelHint = 0; | |
1992 | } | |
1993 | } | |
1994 | ||
1995 | ar->ap_profile_flag = 1; /* There is a change in profile */ | |
1996 | ||
1997 | A_PRINTF("channel hint set to %d\n", ar->arChannelHint); | |
1998 | return 0; | |
1999 | } | |
2000 | ||
2001 | /* | |
2002 | * SIOCGIWFREQ | |
2003 | */ | |
2004 | int | |
2005 | ar6000_ioctl_giwfreq(struct net_device *dev, | |
2006 | struct iw_request_info *info, | |
2007 | struct iw_freq *freq, char *extra) | |
2008 | { | |
a71f0bf6 | 2009 | struct ar6_softc *ar = (struct ar6_softc *)ar6k_priv(dev); |
30295c89 | 2010 | |
4f69cef0 | 2011 | if (is_iwioctl_allowed(ar->arNextMode, info->cmd) != 0) { |
30295c89 VM |
2012 | A_PRINTF("wext_ioctl: cmd=0x%x not allowed in this mode\n", info->cmd); |
2013 | return -EOPNOTSUPP; | |
2014 | } | |
2015 | ||
2016 | if (ar->arWlanState == WLAN_DISABLED) { | |
2017 | return -EIO; | |
2018 | } | |
2019 | ||
2020 | if (ar->arNetworkType == AP_NETWORK) { | |
2021 | if(ar->arChannelHint) { | |
2022 | freq->m = ar->arChannelHint * 100000; | |
2023 | } else if(ar->arACS) { | |
2024 | freq->m = ar->arACS * 100000; | |
2025 | } else { | |
2026 | return -EINVAL; | |
2027 | } | |
2028 | } else { | |
1071a134 | 2029 | if (ar->arConnected != true) { |
30295c89 VM |
2030 | return -EINVAL; |
2031 | } else { | |
2032 | freq->m = ar->arBssChannel * 100000; | |
2033 | } | |
2034 | } | |
2035 | ||
2036 | freq->e = 1; | |
2037 | ||
2038 | return 0; | |
2039 | } | |
2040 | ||
2041 | /* | |
2042 | * SIOCSIWMODE | |
2043 | */ | |
2044 | int | |
2045 | ar6000_ioctl_siwmode(struct net_device *dev, | |
2046 | struct iw_request_info *info, | |
2047 | __u32 *mode, char *extra) | |
2048 | { | |
a71f0bf6 | 2049 | struct ar6_softc *ar = (struct ar6_softc *)ar6k_priv(dev); |
30295c89 | 2050 | |
4f69cef0 | 2051 | if (is_iwioctl_allowed(ar->arNextMode, info->cmd) != 0) { |
30295c89 VM |
2052 | A_PRINTF("wext_ioctl: cmd=0x%x not allowed in this mode\n", info->cmd); |
2053 | return -EOPNOTSUPP; | |
2054 | } | |
2055 | ||
2056 | if (ar->arWlanState == WLAN_DISABLED) { | |
2057 | return -EIO; | |
2058 | } | |
2059 | ||
2060 | /* | |
2061 | * clear SSID during mode switch in connected state | |
2062 | */ | |
1071a134 | 2063 | if(!(ar->arNetworkType == (((*mode) == IW_MODE_INFRA) ? INFRA_NETWORK : ADHOC_NETWORK)) && (ar->arConnected == true) ){ |
30295c89 VM |
2064 | A_MEMZERO(ar->arSsid, sizeof(ar->arSsid)); |
2065 | ar->arSsidLen = 0; | |
2066 | } | |
2067 | ||
2068 | switch (*mode) { | |
2069 | case IW_MODE_INFRA: | |
2070 | ar->arNextMode = INFRA_NETWORK; | |
2071 | break; | |
2072 | case IW_MODE_ADHOC: | |
2073 | ar->arNextMode = ADHOC_NETWORK; | |
2074 | break; | |
2075 | case IW_MODE_MASTER: | |
2076 | ar->arNextMode = AP_NETWORK; | |
2077 | break; | |
2078 | default: | |
2079 | return -EINVAL; | |
2080 | } | |
2081 | ||
2082 | /* clear all shared parameters between AP and STA|IBSS modes when we | |
2083 | * switch between them. Switch between STA & IBSS modes does'nt clear | |
2084 | * the shared profile. This is as per the original design for switching | |
2085 | * between STA & IBSS. | |
2086 | */ | |
2087 | if (ar->arNetworkType == AP_NETWORK || ar->arNextMode == AP_NETWORK) { | |
2088 | ar->arDot11AuthMode = OPEN_AUTH; | |
2089 | ar->arAuthMode = NONE_AUTH; | |
2090 | ar->arPairwiseCrypto = NONE_CRYPT; | |
2091 | ar->arPairwiseCryptoLen = 0; | |
2092 | ar->arGroupCrypto = NONE_CRYPT; | |
2093 | ar->arGroupCryptoLen = 0; | |
2094 | ar->arChannelHint = 0; | |
2095 | ar->arBssChannel = 0; | |
2096 | A_MEMZERO(ar->arBssid, sizeof(ar->arBssid)); | |
2097 | A_MEMZERO(ar->arSsid, sizeof(ar->arSsid)); | |
2098 | ar->arSsidLen = 0; | |
2099 | } | |
2100 | ||
2101 | /* SSID has to be cleared to trigger a profile change while switching | |
2102 | * between STA & IBSS modes having the same SSID | |
2103 | */ | |
2104 | if (ar->arNetworkType != ar->arNextMode) { | |
2105 | A_MEMZERO(ar->arSsid, sizeof(ar->arSsid)); | |
2106 | ar->arSsidLen = 0; | |
2107 | } | |
2108 | ||
2109 | return 0; | |
2110 | } | |
2111 | ||
2112 | /* | |
2113 | * SIOCGIWMODE | |
2114 | */ | |
2115 | int | |
2116 | ar6000_ioctl_giwmode(struct net_device *dev, | |
2117 | struct iw_request_info *info, | |
2118 | __u32 *mode, char *extra) | |
2119 | { | |
a71f0bf6 | 2120 | struct ar6_softc *ar = (struct ar6_softc *)ar6k_priv(dev); |
30295c89 | 2121 | |
4f69cef0 | 2122 | if (is_iwioctl_allowed(ar->arNextMode, info->cmd) != 0) { |
30295c89 VM |
2123 | A_PRINTF("wext_ioctl: cmd=0x%x not allowed in this mode\n", info->cmd); |
2124 | return -EOPNOTSUPP; | |
2125 | } | |
2126 | ||
2127 | if (ar->arWlanState == WLAN_DISABLED) { | |
2128 | return -EIO; | |
2129 | } | |
2130 | ||
2131 | switch (ar->arNetworkType) { | |
2132 | case INFRA_NETWORK: | |
2133 | *mode = IW_MODE_INFRA; | |
2134 | break; | |
2135 | case ADHOC_NETWORK: | |
2136 | *mode = IW_MODE_ADHOC; | |
2137 | break; | |
2138 | case AP_NETWORK: | |
2139 | *mode = IW_MODE_MASTER; | |
2140 | break; | |
2141 | default: | |
2142 | return -EIO; | |
2143 | } | |
2144 | return 0; | |
2145 | } | |
2146 | ||
2147 | /* | |
2148 | * SIOCSIWSENS | |
2149 | */ | |
2150 | int | |
2151 | ar6000_ioctl_siwsens(struct net_device *dev, | |
2152 | struct iw_request_info *info, | |
2153 | struct iw_param *sens, char *extra) | |
2154 | { | |
2155 | return 0; | |
2156 | } | |
2157 | ||
2158 | /* | |
2159 | * SIOCGIWSENS | |
2160 | */ | |
2161 | int | |
2162 | ar6000_ioctl_giwsens(struct net_device *dev, | |
2163 | struct iw_request_info *info, | |
2164 | struct iw_param *sens, char *extra) | |
2165 | { | |
2166 | sens->value = 0; | |
2167 | sens->fixed = 1; | |
2168 | ||
2169 | return 0; | |
2170 | } | |
2171 | ||
2172 | /* | |
2173 | * SIOCGIWRANGE | |
2174 | */ | |
2175 | int | |
2176 | ar6000_ioctl_giwrange(struct net_device *dev, | |
2177 | struct iw_request_info *info, | |
2178 | struct iw_point *data, char *extra) | |
2179 | { | |
a71f0bf6 | 2180 | struct ar6_softc *ar = (struct ar6_softc *)ar6k_priv(dev); |
30295c89 VM |
2181 | struct iw_range *range = (struct iw_range *) extra; |
2182 | int i, ret = 0; | |
2183 | ||
4f69cef0 | 2184 | if (is_iwioctl_allowed(ar->arNextMode, info->cmd) != 0) { |
30295c89 VM |
2185 | A_PRINTF("wext_ioctl: cmd=0x%x not allowed in this mode\n", info->cmd); |
2186 | return -EOPNOTSUPP; | |
2187 | } | |
2188 | ||
2189 | if (ar->bIsDestroyProgress) { | |
2190 | return -EBUSY; | |
2191 | } | |
2192 | ||
1071a134 | 2193 | if (ar->arWmiReady == false) { |
30295c89 VM |
2194 | return -EIO; |
2195 | } | |
2196 | ||
2197 | if (down_interruptible(&ar->arSem)) { | |
2198 | return -ERESTARTSYS; | |
2199 | } | |
2200 | ||
2201 | if (ar->bIsDestroyProgress) { | |
2202 | up(&ar->arSem); | |
2203 | return -EBUSY; | |
2204 | } | |
2205 | ||
2206 | ar->arNumChannels = -1; | |
2207 | A_MEMZERO(ar->arChannelList, sizeof (ar->arChannelList)); | |
2208 | ||
4f69cef0 | 2209 | if (wmi_get_channelList_cmd(ar->arWmi) != 0) { |
30295c89 VM |
2210 | up(&ar->arSem); |
2211 | return -EIO; | |
2212 | } | |
2213 | ||
2214 | wait_event_interruptible_timeout(arEvent, ar->arNumChannels != -1, wmitimeout * HZ); | |
2215 | ||
2216 | if (signal_pending(current)) { | |
2217 | up(&ar->arSem); | |
2218 | return -EINTR; | |
2219 | } | |
2220 | ||
2221 | data->length = sizeof(struct iw_range); | |
2222 | A_MEMZERO(range, sizeof(struct iw_range)); | |
2223 | ||
2224 | range->txpower_capa = 0; | |
2225 | ||
2226 | range->min_pmp = 1 * 1024; | |
2227 | range->max_pmp = 65535 * 1024; | |
2228 | range->min_pmt = 1 * 1024; | |
2229 | range->max_pmt = 1000 * 1024; | |
2230 | range->pmp_flags = IW_POWER_PERIOD; | |
2231 | range->pmt_flags = IW_POWER_TIMEOUT; | |
2232 | range->pm_capa = 0; | |
2233 | ||
2234 | range->we_version_compiled = WIRELESS_EXT; | |
2235 | range->we_version_source = 13; | |
2236 | ||
2237 | range->retry_capa = IW_RETRY_LIMIT; | |
2238 | range->retry_flags = IW_RETRY_LIMIT; | |
2239 | range->min_retry = 0; | |
2240 | range->max_retry = 255; | |
2241 | ||
2242 | range->num_frequency = range->num_channels = ar->arNumChannels; | |
2243 | for (i = 0; i < ar->arNumChannels; i++) { | |
2244 | range->freq[i].i = wlan_freq2ieee(ar->arChannelList[i]); | |
2245 | range->freq[i].m = ar->arChannelList[i] * 100000; | |
2246 | range->freq[i].e = 1; | |
2247 | /* | |
2248 | * Linux supports max of 32 channels, bail out once you | |
2249 | * reach the max. | |
2250 | */ | |
2251 | if (i == IW_MAX_FREQUENCIES) { | |
2252 | break; | |
2253 | } | |
2254 | } | |
2255 | ||
2256 | /* Max quality is max field value minus noise floor */ | |
2257 | range->max_qual.qual = 0xff - 161; | |
2258 | ||
2259 | /* | |
2260 | * In order to use dBm measurements, 'level' must be lower | |
2261 | * than any possible measurement (see iw_print_stats() in | |
2262 | * wireless tools). It's unclear how this is meant to be | |
2263 | * done, but setting zero in these values forces dBm and | |
2264 | * the actual numbers are not used. | |
2265 | */ | |
2266 | range->max_qual.level = 0; | |
2267 | range->max_qual.noise = 0; | |
2268 | ||
2269 | range->sensitivity = 3; | |
2270 | ||
2271 | range->max_encoding_tokens = 4; | |
2272 | /* XXX query driver to find out supported key sizes */ | |
2273 | range->num_encoding_sizes = 3; | |
2274 | range->encoding_size[0] = 5; /* 40-bit */ | |
2275 | range->encoding_size[1] = 13; /* 104-bit */ | |
2276 | range->encoding_size[2] = 16; /* 128-bit */ | |
2277 | ||
2278 | range->num_bitrates = 0; | |
2279 | ||
2280 | /* estimated maximum TCP throughput values (bps) */ | |
2281 | range->throughput = 22000000; | |
2282 | ||
2283 | range->min_rts = 0; | |
2284 | range->max_rts = 2347; | |
2285 | range->min_frag = 256; | |
2286 | range->max_frag = 2346; | |
2287 | ||
2288 | up(&ar->arSem); | |
2289 | ||
2290 | return ret; | |
2291 | } | |
2292 | ||
2293 | ||
2294 | /* | |
2295 | * SIOCSIWAP | |
2296 | * This ioctl is used to set the desired bssid for the connect command. | |
2297 | */ | |
2298 | int | |
2299 | ar6000_ioctl_siwap(struct net_device *dev, | |
2300 | struct iw_request_info *info, | |
2301 | struct sockaddr *ap_addr, char *extra) | |
2302 | { | |
a71f0bf6 | 2303 | struct ar6_softc *ar = (struct ar6_softc *)ar6k_priv(dev); |
30295c89 | 2304 | |
4f69cef0 | 2305 | if (is_iwioctl_allowed(ar->arNextMode, info->cmd) != 0) { |
30295c89 VM |
2306 | A_PRINTF("wext_ioctl: cmd=0x%x not allowed in this mode\n", info->cmd); |
2307 | return -EOPNOTSUPP; | |
2308 | } | |
2309 | ||
2310 | if (ar->arWlanState == WLAN_DISABLED) { | |
2311 | return -EIO; | |
2312 | } | |
2313 | ||
2314 | if (ap_addr->sa_family != ARPHRD_ETHER) { | |
2315 | return -EIO; | |
2316 | } | |
2317 | ||
395e1cae | 2318 | if (memcmp(&ap_addr->sa_data, bcast_mac, AR6000_ETH_ADDR_LEN) == 0) { |
30295c89 VM |
2319 | A_MEMZERO(ar->arReqBssid, sizeof(ar->arReqBssid)); |
2320 | } else { | |
05209262 | 2321 | memcpy(ar->arReqBssid, &ap_addr->sa_data, sizeof(ar->arReqBssid)); |
30295c89 VM |
2322 | } |
2323 | ||
2324 | return 0; | |
2325 | } | |
2326 | ||
2327 | /* | |
2328 | * SIOCGIWAP | |
2329 | */ | |
2330 | int | |
2331 | ar6000_ioctl_giwap(struct net_device *dev, | |
2332 | struct iw_request_info *info, | |
2333 | struct sockaddr *ap_addr, char *extra) | |
2334 | { | |
a71f0bf6 | 2335 | struct ar6_softc *ar = (struct ar6_softc *)ar6k_priv(dev); |
30295c89 | 2336 | |
4f69cef0 | 2337 | if (is_iwioctl_allowed(ar->arNextMode, info->cmd) != 0) { |
30295c89 VM |
2338 | A_PRINTF("wext_ioctl: cmd=0x%x not allowed in this mode\n", info->cmd); |
2339 | return -EOPNOTSUPP; | |
2340 | } | |
2341 | ||
2342 | if (ar->arWlanState == WLAN_DISABLED) { | |
2343 | return -EIO; | |
2344 | } | |
2345 | ||
2346 | if (ar->arNetworkType == AP_NETWORK) { | |
05209262 | 2347 | memcpy(&ap_addr->sa_data, dev->dev_addr, ATH_MAC_LEN); |
30295c89 VM |
2348 | ap_addr->sa_family = ARPHRD_ETHER; |
2349 | return 0; | |
2350 | } | |
2351 | ||
1071a134 | 2352 | if (ar->arConnected != true) { |
30295c89 VM |
2353 | return -EINVAL; |
2354 | } | |
2355 | ||
05209262 | 2356 | memcpy(&ap_addr->sa_data, ar->arBssid, sizeof(ar->arBssid)); |
30295c89 VM |
2357 | ap_addr->sa_family = ARPHRD_ETHER; |
2358 | ||
2359 | return 0; | |
2360 | } | |
2361 | ||
2362 | #if (WIRELESS_EXT >= 18) | |
2363 | /* | |
2364 | * SIOCSIWMLME | |
2365 | */ | |
2366 | int | |
2367 | ar6000_ioctl_siwmlme(struct net_device *dev, | |
2368 | struct iw_request_info *info, | |
2369 | struct iw_point *data, char *extra) | |
2370 | { | |
a71f0bf6 | 2371 | struct ar6_softc *ar = (struct ar6_softc *)ar6k_priv(dev); |
30295c89 | 2372 | |
4f69cef0 | 2373 | if (is_iwioctl_allowed(ar->arNextMode, info->cmd) != 0) { |
30295c89 VM |
2374 | A_PRINTF("wext_ioctl: cmd=0x%x not allowed in this mode\n", info->cmd); |
2375 | return -EOPNOTSUPP; | |
2376 | } | |
2377 | ||
2378 | if (ar->bIsDestroyProgress) { | |
2379 | return -EBUSY; | |
2380 | } | |
2381 | ||
2382 | if (ar->arWlanState == WLAN_DISABLED) { | |
2383 | return -EIO; | |
2384 | } | |
2385 | ||
1071a134 | 2386 | if (ar->arWmiReady == false) { |
30295c89 VM |
2387 | return -EIO; |
2388 | } | |
2389 | ||
2390 | if (down_interruptible(&ar->arSem)) { | |
2391 | return -ERESTARTSYS; | |
2392 | } | |
2393 | ||
2394 | if (data->pointer && data->length == sizeof(struct iw_mlme)) { | |
2395 | ||
ab3655da | 2396 | u8 arNetworkType; |
30295c89 VM |
2397 | struct iw_mlme mlme; |
2398 | ||
2399 | if (copy_from_user(&mlme, data->pointer, sizeof(struct iw_mlme))) | |
2400 | return -EIO; | |
2401 | ||
2402 | switch (mlme.cmd) { | |
2403 | ||
2404 | case IW_MLME_DEAUTH: | |
2405 | /* fall through */ | |
2406 | case IW_MLME_DISASSOC: | |
1071a134 | 2407 | if ((ar->arConnected != true) || |
30295c89 VM |
2408 | (memcmp(ar->arBssid, mlme.addr.sa_data, 6) != 0)) { |
2409 | ||
2410 | up(&ar->arSem); | |
2411 | return -EINVAL; | |
2412 | } | |
2413 | wmi_setPmkid_cmd(ar->arWmi, ar->arBssid, NULL, 0); | |
2414 | arNetworkType = ar->arNetworkType; | |
2415 | ar6000_init_profile_info(ar); | |
2416 | ar->arNetworkType = arNetworkType; | |
2417 | reconnect_flag = 0; | |
83195cc8 | 2418 | ar6000_disconnect(ar); |
30295c89 VM |
2419 | A_MEMZERO(ar->arSsid, sizeof(ar->arSsid)); |
2420 | ar->arSsidLen = 0; | |
1071a134 | 2421 | if (ar->arSkipScan == false) { |
30295c89 VM |
2422 | A_MEMZERO(ar->arReqBssid, sizeof(ar->arReqBssid)); |
2423 | } | |
2424 | break; | |
2425 | ||
2426 | case IW_MLME_AUTH: | |
2427 | /* fall through */ | |
2428 | case IW_MLME_ASSOC: | |
2429 | /* fall through */ | |
2430 | default: | |
2431 | up(&ar->arSem); | |
2432 | return -EOPNOTSUPP; | |
2433 | } | |
2434 | } | |
2435 | ||
2436 | up(&ar->arSem); | |
2437 | return 0; | |
2438 | } | |
2439 | #endif /* WIRELESS_EXT >= 18 */ | |
2440 | ||
2441 | /* | |
2442 | * SIOCGIWAPLIST | |
2443 | */ | |
2444 | int | |
2445 | ar6000_ioctl_iwaplist(struct net_device *dev, | |
2446 | struct iw_request_info *info, | |
2447 | struct iw_point *data, char *extra) | |
2448 | { | |
2449 | return -EIO; /* for now */ | |
2450 | } | |
2451 | ||
2452 | /* | |
2453 | * SIOCSIWSCAN | |
2454 | */ | |
2455 | int | |
2456 | ar6000_ioctl_siwscan(struct net_device *dev, | |
2457 | struct iw_request_info *info, | |
2458 | struct iw_point *data, char *extra) | |
2459 | { | |
2460 | #define ACT_DWELLTIME_DEFAULT 105 | |
2461 | #define HOME_TXDRAIN_TIME 100 | |
2462 | #define SCAN_INT HOME_TXDRAIN_TIME + ACT_DWELLTIME_DEFAULT | |
a71f0bf6 | 2463 | struct ar6_softc *ar = (struct ar6_softc *)ar6k_priv(dev); |
30295c89 VM |
2464 | int ret = 0; |
2465 | ||
4f69cef0 | 2466 | if (is_iwioctl_allowed(ar->arNextMode, info->cmd) != 0) { |
30295c89 VM |
2467 | A_PRINTF("wext_ioctl: cmd=0x%x not allowed in this mode\n", info->cmd); |
2468 | return -EOPNOTSUPP; | |
2469 | } | |
2470 | ||
1071a134 | 2471 | if (ar->arWmiReady == false) { |
30295c89 VM |
2472 | return -EIO; |
2473 | } | |
2474 | ||
2475 | if (ar->arWlanState == WLAN_DISABLED) { | |
2476 | return -EIO; | |
2477 | } | |
2478 | ||
2479 | /* If scan is issued in the middle of ongoing scan or connect, | |
2480 | dont issue another one */ | |
2481 | if ( ar->scan_triggered > 0 ) { | |
2482 | ++ar->scan_triggered; | |
2483 | if (ar->scan_triggered < 5) { | |
2484 | return 0; | |
2485 | } else { | |
2486 | AR_DEBUG_PRINTF(ATH_DEBUG_WLAN_SCAN,("Scan request is triggered over 5 times. Not scan complete event\n")); | |
2487 | } | |
2488 | } | |
2489 | ||
2490 | if (!ar->arUserBssFilter) { | |
4f69cef0 | 2491 | if (wmi_bssfilter_cmd(ar->arWmi, ALL_BSS_FILTER, 0) != 0) { |
30295c89 VM |
2492 | return -EIO; |
2493 | } | |
2494 | } | |
2495 | ||
2496 | if (ar->arConnected) { | |
4f69cef0 | 2497 | if (wmi_get_stats_cmd(ar->arWmi) != 0) { |
30295c89 VM |
2498 | return -EIO; |
2499 | } | |
2500 | } | |
2501 | ||
2502 | #ifdef ANDROID_ENV | |
2503 | #if WIRELESS_EXT >= 18 | |
2504 | if (data->pointer && (data->length == sizeof(struct iw_scan_req))) | |
2505 | { | |
2506 | if ((data->flags & IW_SCAN_THIS_ESSID) == IW_SCAN_THIS_ESSID) | |
2507 | { | |
2508 | struct iw_scan_req req; | |
2509 | if (copy_from_user(&req, data->pointer, sizeof(struct iw_scan_req))) | |
2510 | return -EIO; | |
4f69cef0 | 2511 | if (wmi_probedSsid_cmd(ar->arWmi, 1, SPECIFIC_SSID_FLAG, req.essid_len, req.essid) != 0) |
30295c89 | 2512 | return -EIO; |
1071a134 | 2513 | ar->scanSpecificSsid = true; |
30295c89 VM |
2514 | } |
2515 | else | |
2516 | { | |
2517 | if (ar->scanSpecificSsid) { | |
4f69cef0 | 2518 | if (wmi_probedSsid_cmd(ar->arWmi, 1, DISABLE_SSID_FLAG, 0, NULL) != 0) |
30295c89 | 2519 | return -EIO; |
1071a134 | 2520 | ar->scanSpecificSsid = false; |
30295c89 VM |
2521 | } |
2522 | } | |
2523 | } | |
2524 | else | |
2525 | { | |
2526 | if (ar->scanSpecificSsid) { | |
4f69cef0 | 2527 | if (wmi_probedSsid_cmd(ar->arWmi, 1, DISABLE_SSID_FLAG, 0, NULL) != 0) |
30295c89 | 2528 | return -EIO; |
1071a134 | 2529 | ar->scanSpecificSsid = false; |
30295c89 VM |
2530 | } |
2531 | } | |
2532 | #endif | |
2533 | #endif /* ANDROID_ENV */ | |
2534 | ||
1071a134 | 2535 | if (wmi_startscan_cmd(ar->arWmi, WMI_LONG_SCAN, false, false, \ |
4f69cef0 | 2536 | 0, 0, 0, NULL) != 0) { |
30295c89 VM |
2537 | ret = -EIO; |
2538 | } | |
2539 | ||
2540 | if (ret == 0) { | |
2541 | ar->scan_triggered = 1; | |
2542 | } | |
2543 | ||
2544 | return ret; | |
2545 | #undef ACT_DWELLTIME_DEFAULT | |
2546 | #undef HOME_TXDRAIN_TIME | |
2547 | #undef SCAN_INT | |
2548 | } | |
2549 | ||
2550 | ||
2551 | /* | |
2552 | * Units are in db above the noise floor. That means the | |
2553 | * rssi values reported in the tx/rx descriptors in the | |
2554 | * driver are the SNR expressed in db. | |
2555 | * | |
2556 | * If you assume that the noise floor is -95, which is an | |
2557 | * excellent assumption 99.5 % of the time, then you can | |
2558 | * derive the absolute signal level (i.e. -95 + rssi). | |
2559 | * There are some other slight factors to take into account | |
2560 | * depending on whether the rssi measurement is from 11b, | |
2561 | * 11g, or 11a. These differences are at most 2db and | |
2562 | * can be documented. | |
2563 | * | |
2564 | * NB: various calculations are based on the orinoco/wavelan | |
2565 | * drivers for compatibility | |
2566 | */ | |
2567 | static void | |
f2ab1275 | 2568 | ar6000_set_quality(struct iw_quality *iq, s8 rssi) |
30295c89 VM |
2569 | { |
2570 | if (rssi < 0) { | |
2571 | iq->qual = 0; | |
2572 | } else { | |
2573 | iq->qual = rssi; | |
2574 | } | |
2575 | ||
2576 | /* NB: max is 94 because noise is hardcoded to 161 */ | |
2577 | if (iq->qual > 94) | |
2578 | iq->qual = 94; | |
2579 | ||
2580 | iq->noise = 161; /* -95dBm */ | |
2581 | iq->level = iq->noise + iq->qual; | |
2582 | iq->updated = 7; | |
2583 | } | |
2584 | ||
2585 | ||
2586 | int | |
2587 | ar6000_ioctl_siwcommit(struct net_device *dev, | |
2588 | struct iw_request_info *info, | |
2589 | struct iw_point *data, char *extra) | |
2590 | { | |
a71f0bf6 | 2591 | struct ar6_softc *ar = (struct ar6_softc *)ar6k_priv(dev); |
30295c89 | 2592 | |
4f69cef0 | 2593 | if (is_iwioctl_allowed(ar->arNextMode, info->cmd) != 0) { |
30295c89 VM |
2594 | A_PRINTF("wext_ioctl: cmd=0x%x not allowed in this mode\n", info->cmd); |
2595 | return -EOPNOTSUPP; | |
2596 | } | |
2597 | ||
1071a134 | 2598 | if (ar->arWmiReady == false) { |
30295c89 VM |
2599 | return -EIO; |
2600 | } | |
2601 | ||
2602 | if (ar->arWlanState == WLAN_DISABLED) { | |
2603 | return -EIO; | |
2604 | } | |
2605 | ||
2606 | AR_DEBUG_PRINTF(ATH_DEBUG_WLAN_CONNECT,("AP: SSID %s freq %d authmode %d dot11 auth %d"\ | |
2607 | " PW crypto %d GRP crypto %d\n", | |
2608 | ar->arSsid, ar->arChannelHint, | |
2609 | ar->arAuthMode, ar->arDot11AuthMode, | |
2610 | ar->arPairwiseCrypto, ar->arGroupCrypto)); | |
2611 | ||
2612 | ar6000_ap_mode_profile_commit(ar); | |
2613 | ||
2614 | /* if there is a profile switch from STA|IBSS mode to AP mode, | |
2615 | * update the host driver association state for the STA|IBSS mode. | |
2616 | */ | |
2617 | if (ar->arNetworkType != AP_NETWORK && ar->arNextMode == AP_NETWORK) { | |
30295c89 VM |
2618 | /* Stop getting pkts from upper stack */ |
2619 | netif_stop_queue(ar->arNetDev); | |
2620 | A_MEMZERO(ar->arBssid, sizeof(ar->arBssid)); | |
2621 | ar->arBssChannel = 0; | |
2622 | ar->arBeaconInterval = 0; | |
2623 | ||
2624 | /* Flush the Tx queues */ | |
2625 | ar6000_TxDataCleanup(ar); | |
2626 | ||
2627 | /* Start getting pkts from upper stack */ | |
2628 | netif_wake_queue(ar->arNetDev); | |
2629 | } | |
2630 | ||
2631 | return 0; | |
2632 | } | |
2633 | ||
2634 | #define W_PROTO(_x) wait_ ## _x | |
2635 | #define WAIT_HANDLER_IMPL(_x, type) \ | |
2636 | int wait_ ## _x (struct net_device *dev, struct iw_request_info *info, type wrqu, char *extra) {\ | |
2637 | int ret; \ | |
2638 | dev_hold(dev); \ | |
2639 | rtnl_unlock(); \ | |
2640 | ret = _x(dev, info, wrqu, extra); \ | |
2641 | rtnl_lock(); \ | |
2642 | dev_put(dev); \ | |
2643 | return ret;\ | |
2644 | } | |
2645 | ||
2646 | WAIT_HANDLER_IMPL(ar6000_ioctl_siwessid, struct iw_point *) | |
2647 | WAIT_HANDLER_IMPL(ar6000_ioctl_giwrate, struct iw_param *) | |
2648 | WAIT_HANDLER_IMPL(ar6000_ioctl_giwtxpow, struct iw_param *) | |
2649 | WAIT_HANDLER_IMPL(ar6000_ioctl_giwrange, struct iw_point*) | |
2650 | ||
2651 | /* Structures to export the Wireless Handlers */ | |
2652 | static const iw_handler ath_handlers[] = { | |
2653 | (iw_handler) ar6000_ioctl_siwcommit, /* SIOCSIWCOMMIT */ | |
2654 | (iw_handler) ar6000_ioctl_giwname, /* SIOCGIWNAME */ | |
2655 | (iw_handler) NULL, /* SIOCSIWNWID */ | |
2656 | (iw_handler) NULL, /* SIOCGIWNWID */ | |
2657 | (iw_handler) ar6000_ioctl_siwfreq, /* SIOCSIWFREQ */ | |
2658 | (iw_handler) ar6000_ioctl_giwfreq, /* SIOCGIWFREQ */ | |
2659 | (iw_handler) ar6000_ioctl_siwmode, /* SIOCSIWMODE */ | |
2660 | (iw_handler) ar6000_ioctl_giwmode, /* SIOCGIWMODE */ | |
2661 | (iw_handler) ar6000_ioctl_siwsens, /* SIOCSIWSENS */ | |
2662 | (iw_handler) ar6000_ioctl_giwsens, /* SIOCGIWSENS */ | |
2663 | (iw_handler) NULL /* not _used */, /* SIOCSIWRANGE */ | |
2664 | (iw_handler) W_PROTO(ar6000_ioctl_giwrange),/* SIOCGIWRANGE */ | |
2665 | (iw_handler) NULL /* not used */, /* SIOCSIWPRIV */ | |
2666 | (iw_handler) NULL /* kernel code */, /* SIOCGIWPRIV */ | |
2667 | (iw_handler) NULL /* not used */, /* SIOCSIWSTATS */ | |
2668 | (iw_handler) NULL /* kernel code */, /* SIOCGIWSTATS */ | |
2669 | (iw_handler) NULL, /* SIOCSIWSPY */ | |
2670 | (iw_handler) NULL, /* SIOCGIWSPY */ | |
2671 | (iw_handler) NULL, /* SIOCSIWTHRSPY */ | |
2672 | (iw_handler) NULL, /* SIOCGIWTHRSPY */ | |
2673 | (iw_handler) ar6000_ioctl_siwap, /* SIOCSIWAP */ | |
2674 | (iw_handler) ar6000_ioctl_giwap, /* SIOCGIWAP */ | |
2675 | #if (WIRELESS_EXT >= 18) | |
2676 | (iw_handler) ar6000_ioctl_siwmlme, /* SIOCSIWMLME */ | |
2677 | #else | |
2678 | (iw_handler) NULL, /* -- hole -- */ | |
2679 | #endif /* WIRELESS_EXT >= 18 */ | |
2680 | (iw_handler) ar6000_ioctl_iwaplist, /* SIOCGIWAPLIST */ | |
2681 | (iw_handler) ar6000_ioctl_siwscan, /* SIOCSIWSCAN */ | |
2682 | (iw_handler) ar6000_ioctl_giwscan, /* SIOCGIWSCAN */ | |
2683 | (iw_handler) W_PROTO(ar6000_ioctl_siwessid),/* SIOCSIWESSID */ | |
2684 | (iw_handler) ar6000_ioctl_giwessid, /* SIOCGIWESSID */ | |
2685 | (iw_handler) NULL, /* SIOCSIWNICKN */ | |
2686 | (iw_handler) NULL, /* SIOCGIWNICKN */ | |
2687 | (iw_handler) NULL, /* -- hole -- */ | |
2688 | (iw_handler) NULL, /* -- hole -- */ | |
2689 | (iw_handler) ar6000_ioctl_siwrate, /* SIOCSIWRATE */ | |
2690 | (iw_handler) W_PROTO(ar6000_ioctl_giwrate), /* SIOCGIWRATE */ | |
2691 | (iw_handler) NULL, /* SIOCSIWRTS */ | |
2692 | (iw_handler) NULL, /* SIOCGIWRTS */ | |
2693 | (iw_handler) NULL, /* SIOCSIWFRAG */ | |
2694 | (iw_handler) NULL, /* SIOCGIWFRAG */ | |
2695 | (iw_handler) ar6000_ioctl_siwtxpow, /* SIOCSIWTXPOW */ | |
2696 | (iw_handler) W_PROTO(ar6000_ioctl_giwtxpow),/* SIOCGIWTXPOW */ | |
2697 | (iw_handler) ar6000_ioctl_siwretry, /* SIOCSIWRETRY */ | |
2698 | (iw_handler) ar6000_ioctl_giwretry, /* SIOCGIWRETRY */ | |
2699 | (iw_handler) ar6000_ioctl_siwencode, /* SIOCSIWENCODE */ | |
2700 | (iw_handler) ar6000_ioctl_giwencode, /* SIOCGIWENCODE */ | |
2701 | #if WIRELESS_EXT > 20 | |
2702 | (iw_handler) ar6000_ioctl_siwpower, /* SIOCSIWPOWER */ | |
2703 | (iw_handler) ar6000_ioctl_giwpower, /* SIOCGIWPOWER */ | |
2704 | #endif // WIRELESS_EXT > 20 | |
2705 | #if WIRELESS_EXT >= 18 | |
2706 | (iw_handler) NULL, /* -- hole -- */ | |
2707 | (iw_handler) NULL, /* -- hole -- */ | |
2708 | (iw_handler) ar6000_ioctl_siwgenie, /* SIOCSIWGENIE */ | |
2709 | (iw_handler) ar6000_ioctl_giwgenie, /* SIOCGIWGENIE */ | |
2710 | (iw_handler) ar6000_ioctl_siwauth, /* SIOCSIWAUTH */ | |
2711 | (iw_handler) ar6000_ioctl_giwauth, /* SIOCGIWAUTH */ | |
2712 | (iw_handler) ar6000_ioctl_siwencodeext, /* SIOCSIWENCODEEXT */ | |
2713 | (iw_handler) ar6000_ioctl_giwencodeext, /* SIOCGIWENCODEEXT */ | |
2714 | (iw_handler) ar6000_ioctl_siwpmksa, /* SIOCSIWPMKSA */ | |
2715 | #endif // WIRELESS_EXT >= 18 | |
2716 | }; | |
2717 | ||
2718 | struct iw_handler_def ath_iw_handler_def = { | |
2719 | .standard = (iw_handler *)ath_handlers, | |
2720 | .num_standard = ARRAY_SIZE(ath_handlers), | |
2721 | .private = NULL, | |
2722 | .num_private = 0, | |
2723 | }; |