]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - drivers/staging/rtl8712/rtl871x_ioctl_linux.c
Merge branch 'drm-tda998x-devel' of git://ftp.arm.linux.org.uk/~rmk/linux-arm into...
[mirror_ubuntu-artful-kernel.git] / drivers / staging / rtl8712 / rtl871x_ioctl_linux.c
CommitLineData
2865d42c
LF
1/******************************************************************************
2 * rtl871x_ioctl_linux.c
3 *
4 * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
5 * Linux device driver for RTL8192SU
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of version 2 of the GNU General Public License as
9 * published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
19 *
20 * Modifications for inclusion into the Linux staging tree are
21 * Copyright(c) 2010 Larry Finger. All rights reserved.
22 *
23 * Contact information:
24 * WLAN FAE <wlanfae@realtek.com>
25 * Larry Finger <Larry.Finger@lwfinger.net>
26 *
27 ******************************************************************************/
28
29#define _RTL871X_IOCTL_LINUX_C_
e3dc896b 30#define _RTL871X_MP_IOCTL_C_
2865d42c
LF
31
32#include "osdep_service.h"
33#include "drv_types.h"
34#include "wlan_bssdef.h"
35#include "rtl871x_debug.h"
36#include "wifi.h"
37#include "rtl871x_mlme.h"
38#include "rtl871x_ioctl.h"
39#include "rtl871x_ioctl_set.h"
40#include "rtl871x_mp_ioctl.h"
41#include "mlme_osdep.h"
359140aa
AB
42#include <linux/wireless.h>
43#include <linux/module.h>
44#include <linux/kernel.h>
359140aa
AB
45#include <linux/io.h>
46#include <linux/semaphore.h>
47#include <net/iw_handler.h>
48#include <linux/if_arp.h>
2865d42c 49
c6dc001f 50#define RTL_IOCTL_WPA_SUPPLICANT (SIOCIWFIRSTPRIV + 0x1E)
2865d42c
LF
51
52#define SCAN_ITEM_SIZE 768
53#define MAX_CUSTOM_LEN 64
54#define RATE_COUNT 4
55
56
57static const u32 rtl8180_rates[] = {1000000, 2000000, 5500000, 11000000,
58 6000000, 9000000, 12000000, 18000000,
59 24000000, 36000000, 48000000, 54000000};
60
61static const long ieee80211_wlan_frequencies[] = {
62 2412, 2417, 2422, 2427,
63 2432, 2437, 2442, 2447,
64 2452, 2457, 2462, 2467,
65 2472, 2484
66};
67
68static const char * const iw_operation_mode[] = {
69 "Auto", "Ad-Hoc", "Managed", "Master", "Repeater", "Secondary",
70 "Monitor"
71};
72
2865d42c
LF
73/**
74 * hwaddr_aton - Convert ASCII string to MAC address
75 * @txt: MAC address as a string (e.g., "00:11:22:33:44:55")
76 * @addr: Buffer for the MAC address (ETH_ALEN = 6 bytes)
77 * Returns: 0 on success, -1 on failure (e.g., string not a MAC address)
78 */
79static int hwaddr_aton_i(const char *txt, u8 *addr)
80{
81 int i;
82
83 for (i = 0; i < 6; i++) {
84 int a, b;
85
91facdbe 86 a = hex_to_bin(*txt++);
2865d42c
LF
87 if (a < 0)
88 return -1;
91facdbe 89 b = hex_to_bin(*txt++);
2865d42c
LF
90 if (b < 0)
91 return -1;
92 *addr++ = (a << 4) | b;
93 if (i < 5 && *txt++ != ':')
94 return -1;
95 }
96 return 0;
97}
98
99void r8712_indicate_wx_assoc_event(struct _adapter *padapter)
100{
101 union iwreq_data wrqu;
102 struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
103
104 wrqu.ap_addr.sa_family = ARPHRD_ETHER;
105 memcpy(wrqu.ap_addr.sa_data, pmlmepriv->cur_network.network.MacAddress,
106 ETH_ALEN);
107 wireless_send_event(padapter->pnetdev, SIOCGIWAP, &wrqu, NULL);
108}
109
110void r8712_indicate_wx_disassoc_event(struct _adapter *padapter)
111{
112 union iwreq_data wrqu;
113
114 wrqu.ap_addr.sa_family = ARPHRD_ETHER;
115 memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN);
116 wireless_send_event(padapter->pnetdev, SIOCGIWAP, &wrqu, NULL);
117}
118
119static inline void handle_pairwise_key(struct sta_info *psta,
120 struct ieee_param *param,
121 struct _adapter *padapter)
122{
123 /* pairwise key */
124 memcpy(psta->x_UncstKey.skey, param->u.crypt.key,
125 (param->u.crypt. key_len > 16 ? 16 : param->u.crypt.key_len));
126 if (strcmp(param->u.crypt.alg, "TKIP") == 0) { /* set mic key */
127 memcpy(psta->tkiptxmickey. skey, &(param->u.crypt.
128 key[16]), 8);
129 memcpy(psta->tkiprxmickey. skey, &(param->u.crypt.
130 key[24]), 8);
131 padapter->securitypriv. busetkipkey = false;
132 _set_timer(&padapter->securitypriv.tkip_timer, 50);
133 }
134 r8712_setstakey_cmd(padapter, (unsigned char *)psta, true);
135}
136
137static inline void handle_group_key(struct ieee_param *param,
138 struct _adapter *padapter)
139{
140 if (0 < param->u.crypt.idx &&
141 param->u.crypt.idx < 3) {
142 /* group key idx is 1 or 2 */
143 memcpy(padapter->securitypriv.XGrpKey[param->u.crypt.
144 idx-1].skey, param->u.crypt.key, (param->u.crypt.key_len
145 > 16 ? 16 : param->u.crypt.key_len));
146 memcpy(padapter->securitypriv.XGrptxmickey[param->
147 u.crypt.idx-1].skey, &(param->u.crypt.key[16]), 8);
148 memcpy(padapter->securitypriv. XGrprxmickey[param->
149 u.crypt.idx-1].skey, &(param->u.crypt.key[24]), 8);
150 padapter->securitypriv.binstallGrpkey = true;
151 r8712_set_key(padapter, &padapter->securitypriv,
152 param->u.crypt.idx);
153 if (padapter->registrypriv.power_mgnt > PS_MODE_ACTIVE) {
154 if (padapter->registrypriv.power_mgnt != padapter->
155 pwrctrlpriv.pwr_mode)
156 _set_timer(&(padapter->mlmepriv.dhcp_timer),
157 60000);
158 }
159 }
160}
161
162static inline char *translate_scan(struct _adapter *padapter,
163 struct iw_request_info *info,
164 struct wlan_network *pnetwork,
165 char *start, char *stop)
166{
167 struct iw_event iwe;
168 struct ieee80211_ht_cap *pht_capie;
169 char *current_val;
2865d42c
LF
170 s8 *p;
171 u32 i = 0, ht_ielen = 0;
172 u16 cap, ht_cap = false, mcs_rate;
e29d3ebc 173 u8 rssi;
2865d42c
LF
174
175 if ((pnetwork->network.Configuration.DSConfig < 1) ||
176 (pnetwork->network.Configuration.DSConfig > 14)) {
177 if (pnetwork->network.Configuration.DSConfig < 1)
178 pnetwork->network.Configuration.DSConfig = 1;
179 else
180 pnetwork->network.Configuration.DSConfig = 14;
181 }
182 /* AP MAC address */
183 iwe.cmd = SIOCGIWAP;
184 iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
185 memcpy(iwe.u.ap_addr.sa_data, pnetwork->network.MacAddress, ETH_ALEN);
186 start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_ADDR_LEN);
187 /* Add the ESSID */
188 iwe.cmd = SIOCGIWESSID;
189 iwe.u.data.flags = 1;
0024a1e7 190 iwe.u.data.length = min_t(u32, pnetwork->network.Ssid.SsidLength, 32);
2865d42c
LF
191 start = iwe_stream_add_point(info, start, stop, &iwe,
192 pnetwork->network.Ssid.Ssid);
193 /* parsing HT_CAP_IE */
194 p = r8712_get_ie(&pnetwork->network.IEs[12], _HT_CAPABILITY_IE_,
195 &ht_ielen, pnetwork->network.IELength - 12);
196 if (p && ht_ielen > 0) {
197 ht_cap = true;
198 pht_capie = (struct ieee80211_ht_cap *)(p + 2);
0636b460 199 memcpy(&mcs_rate, pht_capie->supp_mcs_set, 2);
2865d42c
LF
200 }
201 /* Add the protocol name */
202 iwe.cmd = SIOCGIWNAME;
203 if ((r8712_is_cckratesonly_included((u8 *)&pnetwork->network.
204 SupportedRates)) == true) {
205 if (ht_cap == true)
206 snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11bn");
207 else
208 snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11b");
209 } else if ((r8712_is_cckrates_included((u8 *)&pnetwork->network.
210 SupportedRates)) == true) {
211 if (ht_cap == true)
212 snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11bgn");
213 else
214 snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11bg");
215 } else {
216 if (ht_cap == true)
217 snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11gn");
218 else
219 snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11g");
220 }
221 start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_CHAR_LEN);
222 /* Add mode */
223 iwe.cmd = SIOCGIWMODE;
224 memcpy((u8 *)&cap, r8712_get_capability_from_ie(pnetwork->network.IEs),
225 2);
226 cap = le16_to_cpu(cap);
227 if (cap & (WLAN_CAPABILITY_IBSS|WLAN_CAPABILITY_BSS)) {
228 if (cap & WLAN_CAPABILITY_BSS)
229 iwe.u.mode = (u32)IW_MODE_MASTER;
230 else
231 iwe.u.mode = (u32)IW_MODE_ADHOC;
232 start = iwe_stream_add_event(info, start, stop, &iwe,
233 IW_EV_UINT_LEN);
234 }
235 /* Add frequency/channel */
236 iwe.cmd = SIOCGIWFREQ;
237 {
be10ac2b 238 /* check legal index */
2865d42c 239 u8 dsconfig = pnetwork->network.Configuration.DSConfig;
02a29d2d 240
2865d42c
LF
241 if (dsconfig >= 1 && dsconfig <= sizeof(
242 ieee80211_wlan_frequencies) / sizeof(long))
243 iwe.u.freq.m = (s32)(ieee80211_wlan_frequencies[
244 pnetwork->network.Configuration.
245 DSConfig - 1] * 100000);
246 else
247 iwe.u.freq.m = 0;
248 }
249 iwe.u.freq.e = (s16)1;
250 iwe.u.freq.i = (u8)pnetwork->network.Configuration.DSConfig;
251 start = iwe_stream_add_event(info, start, stop, &iwe,
252 IW_EV_FREQ_LEN);
253 /* Add encryption capability */
254 iwe.cmd = SIOCGIWENCODE;
255 if (cap & WLAN_CAPABILITY_PRIVACY)
256 iwe.u.data.flags = (u16)(IW_ENCODE_ENABLED |
257 IW_ENCODE_NOKEY);
258 else
259 iwe.u.data.flags = (u16)(IW_ENCODE_DISABLED);
260 iwe.u.data.length = (u16)0;
261 start = iwe_stream_add_point(info, start, stop, &iwe,
262 pnetwork->network.Ssid.Ssid);
263 /*Add basic and extended rates */
264 current_val = start + iwe_stream_lcp_len(info);
265 iwe.cmd = SIOCGIWRATE;
266 iwe.u.bitrate.fixed = 0;
267 iwe.u.bitrate.disabled = 0;
268 iwe.u.bitrate.value = 0;
269 i = 0;
270 while (pnetwork->network.SupportedRates[i] != 0) {
271 /* Bit rate given in 500 kb/s units */
272 iwe.u.bitrate.value = (pnetwork->network.SupportedRates[i++] &
273 0x7F) * 500000;
274 current_val = iwe_stream_add_value(info, start, current_val,
275 stop, &iwe, IW_EV_PARAM_LEN);
276 }
277 /* Check if we added any event */
278 if ((current_val - start) > iwe_stream_lcp_len(info))
279 start = current_val;
280 /* parsing WPA/WPA2 IE */
281 {
c13b6f24
AB
282 u8 buf[MAX_WPA_IE_LEN];
283 u8 wpa_ie[255], rsn_ie[255];
2865d42c 284 u16 wpa_len = 0, rsn_len = 0;
d936435f 285 int n;
02a29d2d 286
e29d3ebc
SM
287 r8712_get_sec_ie(pnetwork->network.IEs,
288 pnetwork->network.IELength, rsn_ie, &rsn_len,
289 wpa_ie, &wpa_len);
2865d42c 290 if (wpa_len > 0) {
2865d42c 291 memset(buf, 0, MAX_WPA_IE_LEN);
d936435f
DC
292 n = sprintf(buf, "wpa_ie=");
293 for (i = 0; i < wpa_len; i++) {
2657c30e
JM
294 n += snprintf(buf + n, MAX_WPA_IE_LEN - n,
295 "%02x", wpa_ie[i]);
d936435f
DC
296 if (n >= MAX_WPA_IE_LEN)
297 break;
298 }
2865d42c
LF
299 memset(&iwe, 0, sizeof(iwe));
300 iwe.cmd = IWEVCUSTOM;
301 iwe.u.data.length = (u16)strlen(buf);
302 start = iwe_stream_add_point(info, start, stop,
303 &iwe, buf);
304 memset(&iwe, 0, sizeof(iwe));
305 iwe.cmd = IWEVGENIE;
306 iwe.u.data.length = (u16)wpa_len;
307 start = iwe_stream_add_point(info, start, stop,
308 &iwe, wpa_ie);
309 }
310 if (rsn_len > 0) {
2865d42c 311 memset(buf, 0, MAX_WPA_IE_LEN);
d936435f
DC
312 n = sprintf(buf, "rsn_ie=");
313 for (i = 0; i < rsn_len; i++) {
2657c30e
JM
314 n += snprintf(buf + n, MAX_WPA_IE_LEN - n,
315 "%02x", rsn_ie[i]);
d936435f
DC
316 if (n >= MAX_WPA_IE_LEN)
317 break;
318 }
2865d42c
LF
319 memset(&iwe, 0, sizeof(iwe));
320 iwe.cmd = IWEVCUSTOM;
321 iwe.u.data.length = strlen(buf);
322 start = iwe_stream_add_point(info, start, stop,
323 &iwe, buf);
324 memset(&iwe, 0, sizeof(iwe));
325 iwe.cmd = IWEVGENIE;
326 iwe.u.data.length = rsn_len;
327 start = iwe_stream_add_point(info, start, stop, &iwe,
328 rsn_ie);
329 }
330 }
331
332 { /* parsing WPS IE */
c13b6f24 333 u8 wps_ie[512];
2865d42c
LF
334 uint wps_ielen;
335
336 if (r8712_get_wps_ie(pnetwork->network.IEs,
337 pnetwork->network.IELength,
338 wps_ie, &wps_ielen) == true) {
339 if (wps_ielen > 2) {
340 iwe.cmd = IWEVGENIE;
341 iwe.u.data.length = (u16)wps_ielen;
342 start = iwe_stream_add_point(info, start, stop,
343 &iwe, wps_ie);
344 }
345 }
346 }
347 /* Add quality statistics */
348 iwe.cmd = IWEVQUAL;
349 rssi = r8712_signal_scale_mapping(pnetwork->network.Rssi);
350 /* we only update signal_level (signal strength) that is rssi. */
351 iwe.u.qual.updated = (u8)(IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_UPDATED |
352 IW_QUAL_NOISE_INVALID);
353 iwe.u.qual.level = rssi; /* signal strength */
354 iwe.u.qual.qual = 0; /* signal quality */
355 iwe.u.qual.noise = 0; /* noise level */
356 start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_QUAL_LEN);
357 /* how to translate rssi to ?% */
2865d42c
LF
358 return start;
359}
360
361static int wpa_set_auth_algs(struct net_device *dev, u32 value)
362{
7c1f4203 363 struct _adapter *padapter = (struct _adapter *) netdev_priv(dev);
2865d42c
LF
364 int ret = 0;
365
366 if ((value & AUTH_ALG_SHARED_KEY) && (value & AUTH_ALG_OPEN_SYSTEM)) {
367 padapter->securitypriv.ndisencryptstatus =
368 Ndis802_11Encryption1Enabled;
369 padapter->securitypriv.ndisauthtype =
370 Ndis802_11AuthModeAutoSwitch;
371 padapter->securitypriv.AuthAlgrthm = 3;
372 } else if (value & AUTH_ALG_SHARED_KEY) {
373 padapter->securitypriv.ndisencryptstatus =
374 Ndis802_11Encryption1Enabled;
375 padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeShared;
376 padapter->securitypriv.AuthAlgrthm = 1;
377 } else if (value & AUTH_ALG_OPEN_SYSTEM) {
378 if (padapter->securitypriv.ndisauthtype <
379 Ndis802_11AuthModeWPAPSK) {
380 padapter->securitypriv.ndisauthtype =
381 Ndis802_11AuthModeOpen;
382 padapter->securitypriv.AuthAlgrthm = 0;
383 }
384 } else
385 ret = -EINVAL;
386 return ret;
387}
388
389static int wpa_set_encryption(struct net_device *dev, struct ieee_param *param,
390 u32 param_len)
391{
392 int ret = 0;
393 u32 wep_key_idx, wep_key_len = 0;
394 struct NDIS_802_11_WEP *pwep = NULL;
7c1f4203 395 struct _adapter *padapter = (struct _adapter *)netdev_priv(dev);
2865d42c
LF
396 struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
397 struct security_priv *psecuritypriv = &padapter->securitypriv;
398
399 param->u.crypt.err = 0;
400 param->u.crypt.alg[IEEE_CRYPT_ALG_NAME_LEN - 1] = '\0';
401 if (param_len != (u32)((u8 *) param->u.crypt.key - (u8 *)param) +
402 param->u.crypt.key_len)
403 return -EINVAL;
779477f2 404 if (is_broadcast_ether_addr(param->sta_addr)) {
2865d42c
LF
405 if (param->u.crypt.idx >= WEP_KEYS) {
406 /* for large key indices, set the default (0) */
407 param->u.crypt.idx = 0;
408 }
409 } else
410 return -EINVAL;
411 if (strcmp(param->u.crypt.alg, "WEP") == 0) {
87a573ad 412 netdev_info(dev, "r8712u: %s: crypt.alg = WEP\n", __func__);
2865d42c
LF
413 padapter->securitypriv.ndisencryptstatus =
414 Ndis802_11Encryption1Enabled;
415 padapter->securitypriv.PrivacyAlgrthm = _WEP40_;
416 padapter->securitypriv.XGrpPrivacy = _WEP40_;
417 wep_key_idx = param->u.crypt.idx;
418 wep_key_len = param->u.crypt.key_len;
419 if (wep_key_idx >= WEP_KEYS)
420 wep_key_idx = 0;
421 if (wep_key_len > 0) {
422 wep_key_len = wep_key_len <= 5 ? 5 : 13;
91d435fe 423 pwep = kmalloc((u32)(wep_key_len +
57b6686e
TP
424 FIELD_OFFSET(struct NDIS_802_11_WEP,
425 KeyMaterial)), GFP_ATOMIC);
2865d42c
LF
426 if (pwep == NULL)
427 return -ENOMEM;
428 memset(pwep, 0, sizeof(struct NDIS_802_11_WEP));
429 pwep->KeyLength = wep_key_len;
430 pwep->Length = wep_key_len +
431 FIELD_OFFSET(struct NDIS_802_11_WEP,
432 KeyMaterial);
433 if (wep_key_len == 13) {
434 padapter->securitypriv.PrivacyAlgrthm =
435 _WEP104_;
436 padapter->securitypriv.XGrpPrivacy =
437 _WEP104_;
438 }
439 } else
440 return -EINVAL;
441 pwep->KeyIndex = wep_key_idx;
442 pwep->KeyIndex |= 0x80000000;
443 memcpy(pwep->KeyMaterial, param->u.crypt.key, pwep->KeyLength);
444 if (param->u.crypt.set_tx) {
445 if (r8712_set_802_11_add_wep(padapter, pwep) ==
446 (u8)_FAIL)
447 ret = -EOPNOTSUPP;
448 } else {
449 /* don't update "psecuritypriv->PrivacyAlgrthm" and
450 * "psecuritypriv->PrivacyKeyIndex=keyid", but can
451 * r8712_set_key to fw/cam
452 */
453 if (wep_key_idx >= WEP_KEYS) {
454 ret = -EOPNOTSUPP;
455 goto exit;
456 }
457 memcpy(&(psecuritypriv->DefKey[wep_key_idx].
458 skey[0]), pwep->KeyMaterial,
459 pwep->KeyLength);
460 psecuritypriv->DefKeylen[wep_key_idx] =
461 pwep->KeyLength;
462 r8712_set_key(padapter, psecuritypriv, wep_key_idx);
463 }
464 goto exit;
465 }
466 if (padapter->securitypriv.AuthAlgrthm == 2) { /* 802_1x */
467 struct sta_info *psta, *pbcmc_sta;
468 struct sta_priv *pstapriv = &padapter->stapriv;
469
470 if (check_fwstate(pmlmepriv, WIFI_STATION_STATE |
471 WIFI_MP_STATE) == true) { /* sta mode */
472 psta = r8712_get_stainfo(pstapriv,
473 get_bssid(pmlmepriv));
474 if (psta) {
475 psta->ieee8021x_blocked = false;
476 if ((padapter->securitypriv.ndisencryptstatus ==
477 Ndis802_11Encryption2Enabled) ||
478 (padapter->securitypriv.ndisencryptstatus ==
479 Ndis802_11Encryption3Enabled))
480 psta->XPrivacy = padapter->
481 securitypriv.PrivacyAlgrthm;
482 if (param->u.crypt.set_tx == 1)
483 handle_pairwise_key(psta, param,
484 padapter);
485 else /* group key */
486 handle_group_key(param, padapter);
487 }
488 pbcmc_sta = r8712_get_bcmc_stainfo(padapter);
489 if (pbcmc_sta) {
490 pbcmc_sta->ieee8021x_blocked = false;
491 if ((padapter->securitypriv.ndisencryptstatus ==
492 Ndis802_11Encryption2Enabled) ||
493 (padapter->securitypriv.ndisencryptstatus ==
494 Ndis802_11Encryption3Enabled))
495 pbcmc_sta->XPrivacy =
496 padapter->securitypriv.
497 PrivacyAlgrthm;
498 }
499 }
500 }
501exit:
646da830 502 kfree(pwep);
2865d42c
LF
503 return ret;
504}
505
506static int r871x_set_wpa_ie(struct _adapter *padapter, char *pie,
507 unsigned short ielen)
508{
e29d3ebc 509 u8 *buf = NULL;
2865d42c
LF
510 int group_cipher = 0, pairwise_cipher = 0;
511 int ret = 0;
512
513 if ((ielen > MAX_WPA_IE_LEN) || (pie == NULL))
514 return -EINVAL;
515 if (ielen) {
91d435fe 516 buf = kmemdup(pie, ielen, GFP_ATOMIC);
2865d42c
LF
517 if (buf == NULL)
518 return -ENOMEM;
2865d42c 519 if (ielen < RSN_HEADER_LEN) {
2192e606 520 ret = -EINVAL;
2865d42c
LF
521 goto exit;
522 }
523 if (r8712_parse_wpa_ie(buf, ielen, &group_cipher,
524 &pairwise_cipher) == _SUCCESS) {
525 padapter->securitypriv.AuthAlgrthm = 2;
526 padapter->securitypriv.ndisauthtype =
527 Ndis802_11AuthModeWPAPSK;
528 }
529 if (r8712_parse_wpa2_ie(buf, ielen, &group_cipher,
530 &pairwise_cipher) == _SUCCESS) {
531 padapter->securitypriv.AuthAlgrthm = 2;
532 padapter->securitypriv.ndisauthtype =
533 Ndis802_11AuthModeWPA2PSK;
534 }
535 switch (group_cipher) {
536 case WPA_CIPHER_NONE:
537 padapter->securitypriv.XGrpPrivacy =
538 _NO_PRIVACY_;
539 padapter->securitypriv.ndisencryptstatus =
540 Ndis802_11EncryptionDisabled;
541 break;
542 case WPA_CIPHER_WEP40:
543 padapter->securitypriv.XGrpPrivacy = _WEP40_;
544 padapter->securitypriv.ndisencryptstatus =
545 Ndis802_11Encryption1Enabled;
546 break;
547 case WPA_CIPHER_TKIP:
548 padapter->securitypriv.XGrpPrivacy = _TKIP_;
549 padapter->securitypriv.ndisencryptstatus =
550 Ndis802_11Encryption2Enabled;
551 break;
552 case WPA_CIPHER_CCMP:
553 padapter->securitypriv.XGrpPrivacy = _AES_;
554 padapter->securitypriv.ndisencryptstatus =
555 Ndis802_11Encryption3Enabled;
556 break;
557 case WPA_CIPHER_WEP104:
558 padapter->securitypriv.XGrpPrivacy = _WEP104_;
559 padapter->securitypriv.ndisencryptstatus =
560 Ndis802_11Encryption1Enabled;
561 break;
562 }
563 switch (pairwise_cipher) {
564 case WPA_CIPHER_NONE:
565 padapter->securitypriv.PrivacyAlgrthm =
566 _NO_PRIVACY_;
567 padapter->securitypriv.ndisencryptstatus =
568 Ndis802_11EncryptionDisabled;
569 break;
570 case WPA_CIPHER_WEP40:
571 padapter->securitypriv.PrivacyAlgrthm = _WEP40_;
572 padapter->securitypriv.ndisencryptstatus =
573 Ndis802_11Encryption1Enabled;
574 break;
575 case WPA_CIPHER_TKIP:
576 padapter->securitypriv.PrivacyAlgrthm = _TKIP_;
577 padapter->securitypriv.ndisencryptstatus =
578 Ndis802_11Encryption2Enabled;
579 break;
580 case WPA_CIPHER_CCMP:
581 padapter->securitypriv.PrivacyAlgrthm = _AES_;
582 padapter->securitypriv.ndisencryptstatus =
583 Ndis802_11Encryption3Enabled;
584 break;
585 case WPA_CIPHER_WEP104:
586 padapter->securitypriv.PrivacyAlgrthm = _WEP104_;
587 padapter->securitypriv.ndisencryptstatus =
588 Ndis802_11Encryption1Enabled;
589 break;
590 }
591 padapter->securitypriv.wps_phase = false;
592 {/* set wps_ie */
593 u16 cnt = 0;
594 u8 eid, wps_oui[4] = {0x0, 0x50, 0xf2, 0x04};
595
596 while (cnt < ielen) {
597 eid = buf[cnt];
598
599 if ((eid == _VENDOR_SPECIFIC_IE_) &&
600 (!memcmp(&buf[cnt+2], wps_oui, 4))) {
87a573ad 601 netdev_info(padapter->pnetdev, "r8712u: SET WPS_IE\n");
2865d42c
LF
602 padapter->securitypriv.wps_ie_len =
603 ((buf[cnt+1] + 2) <
604 (MAX_WPA_IE_LEN << 2)) ?
605 (buf[cnt + 1] + 2) :
606 (MAX_WPA_IE_LEN << 2);
607 memcpy(padapter->securitypriv.wps_ie,
608 &buf[cnt],
609 padapter->securitypriv.wps_ie_len);
610 padapter->securitypriv.wps_phase =
611 true;
87a573ad 612 netdev_info(padapter->pnetdev, "r8712u: SET WPS_IE, wps_phase==true\n");
2865d42c
LF
613 cnt += buf[cnt+1]+2;
614 break;
615 } else
616 cnt += buf[cnt + 1] + 2;
617 }
618 }
619 }
620exit:
621 kfree(buf);
622 return ret;
623}
624
625static int r8711_wx_get_name(struct net_device *dev,
626 struct iw_request_info *info,
627 union iwreq_data *wrqu, char *extra)
628{
7c1f4203 629 struct _adapter *padapter = (struct _adapter *)netdev_priv(dev);
2865d42c
LF
630 u32 ht_ielen = 0;
631 char *p;
632 u8 ht_cap = false;
633 struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
634 struct ndis_wlan_bssid_ex *pcur_bss = &pmlmepriv->cur_network.network;
635 NDIS_802_11_RATES_EX *prates = NULL;
636
637 if (check_fwstate(pmlmepriv, _FW_LINKED|WIFI_ADHOC_MASTER_STATE) ==
638 true) {
639 /* parsing HT_CAP_IE */
640 p = r8712_get_ie(&pcur_bss->IEs[12], _HT_CAPABILITY_IE_,
641 &ht_ielen, pcur_bss->IELength - 12);
642 if (p && ht_ielen > 0)
643 ht_cap = true;
644 prates = &pcur_bss->SupportedRates;
645 if (r8712_is_cckratesonly_included((u8 *)prates) == true) {
646 if (ht_cap == true)
647 snprintf(wrqu->name, IFNAMSIZ,
648 "IEEE 802.11bn");
649 else
650 snprintf(wrqu->name, IFNAMSIZ,
651 "IEEE 802.11b");
652 } else if ((r8712_is_cckrates_included((u8 *)prates)) == true) {
653 if (ht_cap == true)
654 snprintf(wrqu->name, IFNAMSIZ,
655 "IEEE 802.11bgn");
656 else
657 snprintf(wrqu->name, IFNAMSIZ,
658 "IEEE 802.11bg");
659 } else {
660 if (ht_cap == true)
661 snprintf(wrqu->name, IFNAMSIZ,
662 "IEEE 802.11gn");
663 else
664 snprintf(wrqu->name, IFNAMSIZ,
665 "IEEE 802.11g");
666 }
667 } else
668 snprintf(wrqu->name, IFNAMSIZ, "unassociated");
669 return 0;
670}
671
672static const long frequency_list[] = {
673 2412, 2417, 2422, 2427, 2432, 2437, 2442, 2447, 2452, 2457, 2462,
674 2467, 2472, 2484, 4915, 4920, 4925, 4935, 4940, 4945, 4960, 4980,
675 5035, 5040, 5045, 5055, 5060, 5080, 5170, 5180, 5190, 5200, 5210,
676 5220, 5230, 5240, 5260, 5280, 5300, 5320, 5500, 5520, 5540, 5560,
677 5580, 5600, 5620, 5640, 5660, 5680, 5700, 5745, 5765, 5785, 5805,
678 5825
679};
680
681static int r8711_wx_set_freq(struct net_device *dev,
682 struct iw_request_info *info,
683 union iwreq_data *wrqu, char *extra)
684{
7c1f4203 685 struct _adapter *padapter = (struct _adapter *)netdev_priv(dev);
2865d42c
LF
686 struct iw_freq *fwrq = &wrqu->freq;
687 int rc = 0;
688
689/* If setting by frequency, convert to a channel */
690 if ((fwrq->e == 1) &&
691 (fwrq->m >= (int) 2.412e8) &&
692 (fwrq->m <= (int) 2.487e8)) {
693 int f = fwrq->m / 100000;
694 int c = 0;
02a29d2d 695
2865d42c
LF
696 while ((c < 14) && (f != frequency_list[c]))
697 c++;
698 fwrq->e = 0;
699 fwrq->m = c + 1;
700 }
701 /* Setting by channel number */
702 if ((fwrq->m > 14) || (fwrq->e > 0))
703 rc = -EOPNOTSUPP;
704 else {
705 int channel = fwrq->m;
02a29d2d 706
2865d42c
LF
707 if ((channel < 1) || (channel > 14))
708 rc = -EINVAL;
709 else {
710 /* Yes ! We can set it !!! */
711 padapter->registrypriv.channel = channel;
712 }
713 }
714 return rc;
715}
716
717static int r8711_wx_get_freq(struct net_device *dev,
718 struct iw_request_info *info,
719 union iwreq_data *wrqu, char *extra)
720{
7c1f4203 721 struct _adapter *padapter = (struct _adapter *)netdev_priv(dev);
2865d42c
LF
722 struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
723 struct ndis_wlan_bssid_ex *pcur_bss = &pmlmepriv->cur_network.network;
724
725 if (check_fwstate(pmlmepriv, _FW_LINKED) == true) {
726 wrqu->freq.m = ieee80211_wlan_frequencies[
727 pcur_bss->Configuration.DSConfig-1] * 100000;
728 wrqu->freq.e = 1;
729 wrqu->freq.i = pcur_bss->Configuration.DSConfig;
2192e606
AB
730 } else {
731 return -ENOLINK;
732 }
2865d42c
LF
733 return 0;
734}
735
736static int r8711_wx_set_mode(struct net_device *dev,
737 struct iw_request_info *a,
738 union iwreq_data *wrqu, char *b)
739{
7c1f4203 740 struct _adapter *padapter = (struct _adapter *)netdev_priv(dev);
2865d42c
LF
741 enum NDIS_802_11_NETWORK_INFRASTRUCTURE networkType;
742
743 switch (wrqu->mode) {
744 case IW_MODE_AUTO:
745 networkType = Ndis802_11AutoUnknown;
746 break;
747 case IW_MODE_ADHOC:
748 networkType = Ndis802_11IBSS;
749 break;
750 case IW_MODE_MASTER:
751 networkType = Ndis802_11APMode;
752 break;
753 case IW_MODE_INFRA:
754 networkType = Ndis802_11Infrastructure;
755 break;
756 default:
757 return -EINVAL;
758 }
759 if (Ndis802_11APMode == networkType)
760 r8712_setopmode_cmd(padapter, networkType);
761 else
762 r8712_setopmode_cmd(padapter, Ndis802_11AutoUnknown);
2192e606
AB
763
764 r8712_set_802_11_infrastructure_mode(padapter, networkType);
2865d42c
LF
765 return 0;
766}
767
768static int r8711_wx_get_mode(struct net_device *dev, struct iw_request_info *a,
769 union iwreq_data *wrqu, char *b)
770{
7c1f4203 771 struct _adapter *padapter = (struct _adapter *)netdev_priv(dev);
2865d42c
LF
772 struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
773
774 if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true)
775 wrqu->mode = IW_MODE_INFRA;
776 else if (check_fwstate(pmlmepriv,
777 WIFI_ADHOC_MASTER_STATE|WIFI_ADHOC_STATE) == true)
778 wrqu->mode = IW_MODE_ADHOC;
779 else if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true)
780 wrqu->mode = IW_MODE_MASTER;
781 else
782 wrqu->mode = IW_MODE_AUTO;
783 return 0;
784}
785
786static int r871x_wx_set_pmkid(struct net_device *dev,
787 struct iw_request_info *a,
788 union iwreq_data *wrqu, char *extra)
789{
7c1f4203 790 struct _adapter *padapter = (struct _adapter *)netdev_priv(dev);
2865d42c
LF
791 struct security_priv *psecuritypriv = &padapter->securitypriv;
792 struct iw_pmksa *pPMK = (struct iw_pmksa *) extra;
793 u8 strZeroMacAddress[ETH_ALEN] = {0x00};
794 u8 strIssueBssid[ETH_ALEN] = {0x00};
795 u8 j, blInserted = false;
796 int intReturn = false;
797
798/*
799 There are the BSSID information in the bssid.sa_data array.
be10ac2b
JM
800 If cmd is IW_PMKSA_FLUSH, it means the wpa_supplicant wants to clear
801 all the PMKID information. If cmd is IW_PMKSA_ADD, it means the
802 wpa_supplicant wants to add a PMKID/BSSID to driver.
2865d42c 803 If cmd is IW_PMKSA_REMOVE, it means the wpa_supplicant wants to
be10ac2b 804 remove a PMKID/BSSID from driver.
2865d42c
LF
805*/
806 if (pPMK == NULL)
807 return -EINVAL;
808 memcpy(strIssueBssid, pPMK->bssid.sa_data, ETH_ALEN);
809 switch (pPMK->cmd) {
810 case IW_PMKSA_ADD:
811 if (!memcmp(strIssueBssid, strZeroMacAddress, ETH_ALEN))
812 return intReturn;
813 else
814 intReturn = true;
815 blInserted = false;
816 /* overwrite PMKID */
77e73e8c 817 for (j = 0; j < NUM_PMKID_CACHE; j++) {
2865d42c
LF
818 if (!memcmp(psecuritypriv->PMKIDList[j].Bssid,
819 strIssueBssid, ETH_ALEN)) {
820 /* BSSID is matched, the same AP => rewrite
821 * with new PMKID. */
87a573ad
PF
822 netdev_info(dev, "r8712u: %s: BSSID exists in the PMKList.\n",
823 __func__);
2865d42c
LF
824 memcpy(psecuritypriv->PMKIDList[j].PMKID,
825 pPMK->pmkid, IW_PMKID_LEN);
826 psecuritypriv->PMKIDList[j].bUsed = true;
827 psecuritypriv->PMKIDIndex = j + 1;
828 blInserted = true;
829 break;
830 }
831 }
832 if (!blInserted) {
833 /* Find a new entry */
87a573ad
PF
834 netdev_info(dev, "r8712u: %s: Use the new entry index = %d for this PMKID.\n",
835 __func__, psecuritypriv->PMKIDIndex);
2865d42c
LF
836 memcpy(psecuritypriv->PMKIDList[psecuritypriv->
837 PMKIDIndex].Bssid, strIssueBssid, ETH_ALEN);
838 memcpy(psecuritypriv->PMKIDList[psecuritypriv->
839 PMKIDIndex].PMKID, pPMK->pmkid, IW_PMKID_LEN);
840 psecuritypriv->PMKIDList[psecuritypriv->PMKIDIndex].
841 bUsed = true;
77e73e8c 842 psecuritypriv->PMKIDIndex++;
2865d42c
LF
843 if (psecuritypriv->PMKIDIndex == NUM_PMKID_CACHE)
844 psecuritypriv->PMKIDIndex = 0;
845 }
846 break;
847 case IW_PMKSA_REMOVE:
848 intReturn = true;
849 for (j = 0; j < NUM_PMKID_CACHE; j++) {
850 if (!memcmp(psecuritypriv->PMKIDList[j].Bssid,
851 strIssueBssid, ETH_ALEN)) {
852 /* BSSID is matched, the same AP => Remove
853 * this PMKID information and reset it. */
854 memset(psecuritypriv->PMKIDList[j].Bssid,
855 0x00, ETH_ALEN);
856 psecuritypriv->PMKIDList[j].bUsed = false;
857 break;
858 }
859 }
860 break;
861 case IW_PMKSA_FLUSH:
862 memset(psecuritypriv->PMKIDList, 0,
863 sizeof(struct RT_PMKID_LIST) * NUM_PMKID_CACHE);
864 psecuritypriv->PMKIDIndex = 0;
865 intReturn = true;
866 break;
867 default:
87a573ad 868 netdev_info(dev, "r8712u: %s: unknown Command\n", __func__);
2865d42c
LF
869 intReturn = false;
870 break;
871 }
872 return intReturn;
873}
874
875static int r8711_wx_get_sens(struct net_device *dev,
876 struct iw_request_info *info,
877 union iwreq_data *wrqu, char *extra)
878{
879 wrqu->sens.value = 0;
880 wrqu->sens.fixed = 0; /* no auto select */
881 wrqu->sens.disabled = 1;
882 return 0;
883}
884
885static int r8711_wx_get_range(struct net_device *dev,
886 struct iw_request_info *info,
887 union iwreq_data *wrqu, char *extra)
888{
889 struct iw_range *range = (struct iw_range *)extra;
890 u16 val;
891 int i;
892
893 wrqu->data.length = sizeof(*range);
894 memset(range, 0, sizeof(*range));
895 /* Let's try to keep this struct in the same order as in
896 * linux/include/wireless.h
897 */
898
899 /* TODO: See what values we can set, and remove the ones we can't
900 * set, or fill them with some default data.
901 */
902 /* ~5 Mb/s real (802.11b) */
903 range->throughput = 5 * 1000 * 1000;
904 /* TODO: 8711 sensitivity ? */
905 /* signal level threshold range */
906 /* percent values between 0 and 100. */
907 range->max_qual.qual = 100;
908 range->max_qual.level = 100;
909 range->max_qual.noise = 100;
910 range->max_qual.updated = 7; /* Updated all three */
911 range->avg_qual.qual = 92; /* > 8% missed beacons is 'bad' */
be10ac2b 912 /* TODO: Find real 'good' to 'bad' threshold value for RSSI */
2865d42c
LF
913 range->avg_qual.level = 20 + -98;
914 range->avg_qual.noise = 0;
915 range->avg_qual.updated = 7; /* Updated all three */
916 range->num_bitrates = RATE_COUNT;
917 for (i = 0; i < RATE_COUNT && i < IW_MAX_BITRATES; i++)
918 range->bitrate[i] = rtl8180_rates[i];
919 range->min_frag = MIN_FRAG_THRESHOLD;
920 range->max_frag = MAX_FRAG_THRESHOLD;
921 range->pm_capa = 0;
922 range->we_version_compiled = WIRELESS_EXT;
923 range->we_version_source = 16;
924 range->num_channels = 14;
925 for (i = 0, val = 0; i < 14; i++) {
926 /* Include only legal frequencies for some countries */
927 range->freq[val].i = i + 1;
928 range->freq[val].m = ieee80211_wlan_frequencies[i] * 100000;
929 range->freq[val].e = 1;
930 val++;
931 if (val == IW_MAX_FREQUENCIES)
932 break;
933 }
934 range->num_frequency = val;
935 range->enc_capa = IW_ENC_CAPA_WPA |
936 IW_ENC_CAPA_WPA2 |
937 IW_ENC_CAPA_CIPHER_TKIP |
938 IW_ENC_CAPA_CIPHER_CCMP;
939 return 0;
940}
941
c6dc001f
AB
942static int r8711_wx_get_rate(struct net_device *dev,
943 struct iw_request_info *info,
944 union iwreq_data *wrqu, char *extra);
945
2865d42c
LF
946static int r871x_wx_set_priv(struct net_device *dev,
947 struct iw_request_info *info,
948 union iwreq_data *awrq,
949 char *extra)
950{
951 int ret = 0, len = 0;
952 char *ext;
c6dc001f 953 struct _adapter *padapter = netdev_priv(dev);
2865d42c
LF
954 struct iw_point *dwrq = (struct iw_point *)awrq;
955
956 len = dwrq->length;
91d435fe
VO
957 ext = memdup_user(dwrq->pointer, len);
958 if (IS_ERR(ext))
959 return PTR_ERR(ext);
c6dc001f
AB
960
961 if (0 == strcasecmp(ext, "RSSI")) {
962 /*Return received signal strength indicator in -db for */
963 /* current AP */
964 /*<ssid> Rssi xx */
965 struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
966 struct wlan_network *pcur_network = &pmlmepriv->cur_network;
967 /*static u8 xxxx; */
968 if (check_fwstate(pmlmepriv, _FW_LINKED) == true) {
969 sprintf(ext, "%s rssi %d",
970 pcur_network->network.Ssid.Ssid,
971 /*(xxxx=xxxx+10) */
972 ((padapter->recvpriv.fw_rssi)>>1)-95
973 /*pcur_network->network.Rssi */
974 );
975 } else {
976 sprintf(ext, "OK");
977 }
978 } else if (0 == strcasecmp(ext, "LINKSPEED")) {
979 /*Return link speed in MBPS */
980 /*LinkSpeed xx */
981 union iwreq_data wrqd;
982 int ret_inner;
983 int mbps;
984
985 ret_inner = r8711_wx_get_rate(dev, info, &wrqd, extra);
986 if (0 != ret_inner)
987 mbps = 0;
988 else
989 mbps = wrqd.bitrate.value / 1000000;
990 sprintf(ext, "LINKSPEED %d", mbps);
991 } else if (0 == strcasecmp(ext, "MACADDR")) {
992 /*Return mac address of the station */
87fa05e8
AS
993 /* Macaddr = xx:xx:xx:xx:xx:xx */
994 sprintf(ext, "MACADDR = %pM", dev->dev_addr);
c6dc001f
AB
995 } else if (0 == strcasecmp(ext, "SCAN-ACTIVE")) {
996 /*Set scan type to active */
997 /*OK if successful */
998 struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
02a29d2d 999
c6dc001f
AB
1000 pmlmepriv->passive_mode = 1;
1001 sprintf(ext, "OK");
1002 } else if (0 == strcasecmp(ext, "SCAN-PASSIVE")) {
1003 /*Set scan type to passive */
1004 /*OK if successful */
1005 struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
02a29d2d 1006
c6dc001f
AB
1007 pmlmepriv->passive_mode = 0;
1008 sprintf(ext, "OK");
1009 } else if (0 == strncmp(ext, "DCE-E", 5)) {
1010 /*Set scan type to passive */
1011 /*OK if successful */
1012 r8712_disconnectCtrlEx_cmd(padapter
1013 , 1 /*u32 enableDrvCtrl */
1014 , 5 /*u32 tryPktCnt */
1015 , 100 /*u32 tryPktInterval */
1016 , 5000 /*u32 firstStageTO */
1017 );
1018 sprintf(ext, "OK");
1019 } else if (0 == strncmp(ext, "DCE-D", 5)) {
1020 /*Set scan type to passive */
1021 /*OK if successfu */
1022 r8712_disconnectCtrlEx_cmd(padapter
1023 , 0 /*u32 enableDrvCtrl */
1024 , 5 /*u32 tryPktCnt */
1025 , 100 /*u32 tryPktInterval */
1026 , 5000 /*u32 firstStageTO */
1027 );
1028 sprintf(ext, "OK");
1029 } else {
87a573ad
PF
1030 netdev_info(dev, "r8712u: %s: unknown Command %s.\n",
1031 __func__, ext);
c6dc001f
AB
1032 goto FREE_EXT;
1033 }
1034 if (copy_to_user(dwrq->pointer, ext,
1035 min(dwrq->length, (__u16)(strlen(ext)+1))))
1036 ret = -EFAULT;
1037
1038FREE_EXT:
2865d42c
LF
1039 kfree(ext);
1040 return ret;
1041}
1042
1043/* set bssid flow
1044 * s1. set_802_11_infrastructure_mode()
1045 * s2. set_802_11_authentication_mode()
1046 * s3. set_802_11_encryption_mode()
1047 * s4. set_802_11_bssid()
d1661dfd
AB
1048 *
1049 * This function intends to handle the Set AP command, which specifies the
1050 * MAC# of a preferred Access Point.
1051 * Currently, the request comes via Wireless Extensions' SIOCSIWAP ioctl.
1052 *
be10ac2b 1053 * For this operation to succeed, there is no need for the interface to be up.
d1661dfd 1054 *
2865d42c
LF
1055 */
1056static int r8711_wx_set_wap(struct net_device *dev,
1057 struct iw_request_info *info,
1058 union iwreq_data *awrq,
1059 char *extra)
1060{
1061 int ret = -EINPROGRESS;
7c1f4203 1062 struct _adapter *padapter = (struct _adapter *) netdev_priv(dev);
2865d42c
LF
1063 struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
1064 struct __queue *queue = &pmlmepriv->scanned_queue;
1065 struct sockaddr *temp = (struct sockaddr *)awrq;
1066 unsigned long irqL;
1067 struct list_head *phead;
1068 u8 *dst_bssid;
1069 struct wlan_network *pnetwork = NULL;
1070 enum NDIS_802_11_AUTHENTICATION_MODE authmode;
1071
2865d42c 1072 if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == true)
2192e606 1073 return -EBUSY;
2865d42c
LF
1074 if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING) == true)
1075 return ret;
1076 if (temp->sa_family != ARPHRD_ETHER)
1077 return -EINVAL;
1078 authmode = padapter->securitypriv.ndisauthtype;
1079 spin_lock_irqsave(&queue->lock, irqL);
e99a428a 1080 phead = &queue->queue;
849fb0a8 1081 pmlmepriv->pscanned = phead->next;
2865d42c
LF
1082 while (1) {
1083 if (end_of_queue_search(phead, pmlmepriv->pscanned) == true)
1084 break;
1085 pnetwork = LIST_CONTAINOR(pmlmepriv->pscanned,
1086 struct wlan_network, list);
849fb0a8 1087 pmlmepriv->pscanned = pmlmepriv->pscanned->next;
2865d42c
LF
1088 dst_bssid = pnetwork->network.MacAddress;
1089 if (!memcmp(dst_bssid, temp->sa_data, ETH_ALEN)) {
2192e606
AB
1090 r8712_set_802_11_infrastructure_mode(padapter,
1091 pnetwork->network.InfrastructureMode);
2865d42c
LF
1092 break;
1093 }
1094 }
1095 spin_unlock_irqrestore(&queue->lock, irqL);
1096 if (!ret) {
1097 if (!r8712_set_802_11_authentication_mode(padapter, authmode))
2192e606 1098 ret = -ENOMEM;
2865d42c
LF
1099 else {
1100 if (!r8712_set_802_11_bssid(padapter, temp->sa_data))
1101 ret = -1;
1102 }
1103 }
1104 return ret;
1105}
1106
1107static int r8711_wx_get_wap(struct net_device *dev,
1108 struct iw_request_info *info,
1109 union iwreq_data *wrqu, char *extra)
1110{
7c1f4203 1111 struct _adapter *padapter = (struct _adapter *)netdev_priv(dev);
2865d42c
LF
1112 struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
1113 struct ndis_wlan_bssid_ex *pcur_bss = &pmlmepriv->cur_network.network;
1114
1115 wrqu->ap_addr.sa_family = ARPHRD_ETHER;
2df29e7b
CR
1116 if (check_fwstate(pmlmepriv, _FW_LINKED | WIFI_ADHOC_MASTER_STATE |
1117 WIFI_AP_STATE))
2865d42c 1118 memcpy(wrqu->ap_addr.sa_data, pcur_bss->MacAddress, ETH_ALEN);
2df29e7b
CR
1119 else
1120 memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN);
2865d42c
LF
1121 return 0;
1122}
1123
1124static int r871x_wx_set_mlme(struct net_device *dev,
1125 struct iw_request_info *info,
1126 union iwreq_data *wrqu, char *extra)
1127{
1128 int ret = 0;
7c1f4203 1129 struct _adapter *padapter = (struct _adapter *)netdev_priv(dev);
2865d42c
LF
1130 struct iw_mlme *mlme = (struct iw_mlme *) extra;
1131
1132 if (mlme == NULL)
1133 return -1;
2865d42c
LF
1134 switch (mlme->cmd) {
1135 case IW_MLME_DEAUTH:
1136 if (!r8712_set_802_11_disassociate(padapter))
1137 ret = -1;
1138 break;
1139 case IW_MLME_DISASSOC:
1140 if (!r8712_set_802_11_disassociate(padapter))
1141 ret = -1;
1142 break;
1143 default:
1144 return -EOPNOTSUPP;
1145 }
1146 return ret;
1147}
1148
d1661dfd
AB
1149/**
1150 *
1151 * This function intends to handle the Set Scan command.
1152 * Currently, the request comes via Wireless Extensions' SIOCSIWSCAN ioctl.
1153 *
1154 * For this operation to succeed, the interface is brought Up beforehand.
1155 *
1156 */
2865d42c
LF
1157static int r8711_wx_set_scan(struct net_device *dev,
1158 struct iw_request_info *a,
1159 union iwreq_data *wrqu, char *extra)
1160{
7c1f4203 1161 struct _adapter *padapter = (struct _adapter *)netdev_priv(dev);
2865d42c
LF
1162 struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
1163 u8 status = true;
1164
1165 if (padapter->bDriverStopped == true) {
87a573ad
PF
1166 netdev_info(dev, "In %s: bDriverStopped=%d\n",
1167 __func__, padapter->bDriverStopped);
2865d42c
LF
1168 return -1;
1169 }
1170 if (padapter->bup == false)
2192e606 1171 return -ENETDOWN;
2865d42c
LF
1172 if (padapter->hw_init_completed == false)
1173 return -1;
1174 if ((check_fwstate(pmlmepriv, _FW_UNDER_SURVEY|_FW_UNDER_LINKING)) ||
1175 (pmlmepriv->sitesurveyctrl.traffic_busy == true))
1176 return 0;
1177 if (wrqu->data.length == sizeof(struct iw_scan_req)) {
1178 struct iw_scan_req *req = (struct iw_scan_req *)extra;
02a29d2d 1179
2865d42c
LF
1180 if (wrqu->data.flags & IW_SCAN_THIS_ESSID) {
1181 struct ndis_802_11_ssid ssid;
1182 unsigned long irqL;
0024a1e7 1183 u32 len = min_t(u8, req->essid_len, IW_ESSID_MAX_SIZE);
02a29d2d 1184
2865d42c
LF
1185 memset((unsigned char *)&ssid, 0,
1186 sizeof(struct ndis_802_11_ssid));
1187 memcpy(ssid.Ssid, req->essid, len);
1188 ssid.SsidLength = len;
1189 spin_lock_irqsave(&pmlmepriv->lock, irqL);
1190 if ((check_fwstate(pmlmepriv, _FW_UNDER_SURVEY |
1191 _FW_UNDER_LINKING)) ||
1192 (pmlmepriv->sitesurveyctrl.traffic_busy == true)) {
1193 if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING))
1194 status = false;
1195 } else
1196 status = r8712_sitesurvey_cmd(padapter, &ssid);
1197 spin_unlock_irqrestore(&pmlmepriv->lock, irqL);
1198 }
1199 } else
1200 status = r8712_set_802_11_bssid_list_scan(padapter);
1201 if (status == false)
1202 return -1;
1203 return 0;
1204}
1205
1206static int r8711_wx_get_scan(struct net_device *dev,
1207 struct iw_request_info *a,
1208 union iwreq_data *wrqu, char *extra)
1209{
7c1f4203 1210 struct _adapter *padapter = (struct _adapter *)netdev_priv(dev);
2865d42c
LF
1211 struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
1212 struct __queue *queue = &pmlmepriv->scanned_queue;
1213 struct wlan_network *pnetwork = NULL;
1214 unsigned long irqL;
1215 struct list_head *plist, *phead;
1216 char *ev = extra;
1217 char *stop = ev + wrqu->data.length;
1218 u32 ret = 0, cnt = 0;
1219
1220 if (padapter->bDriverStopped)
1221 return -EINVAL;
1222 while (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY|_FW_UNDER_LINKING)) {
1223 msleep(30);
1224 cnt++;
c6dc001f 1225 if (cnt > 100)
2865d42c
LF
1226 break;
1227 }
1228 spin_lock_irqsave(&queue->lock, irqL);
e99a428a 1229 phead = &queue->queue;
849fb0a8 1230 plist = phead->next;
2865d42c
LF
1231 while (1) {
1232 if (end_of_queue_search(phead, plist) == true)
1233 break;
1234 if ((stop - ev) < SCAN_ITEM_SIZE) {
1235 ret = -E2BIG;
1236 break;
1237 }
1238 pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
1239 ev = translate_scan(padapter, a, pnetwork, ev, stop);
849fb0a8 1240 plist = plist->next;
2865d42c
LF
1241 }
1242 spin_unlock_irqrestore(&queue->lock, irqL);
1243 wrqu->data.length = ev - extra;
1244 wrqu->data.flags = 0;
1245 return ret;
1246}
1247
1248/* set ssid flow
1249 * s1. set_802_11_infrastructure_mode()
1250 * s2. set_802_11_authenticaion_mode()
1251 * s3. set_802_11_encryption_mode()
1252 * s4. set_802_11_ssid()
d1661dfd
AB
1253 *
1254 * This function intends to handle the Set ESSID command.
1255 * Currently, the request comes via the Wireless Extensions' SIOCSIWESSID ioctl.
1256 *
1257 * For this operation to succeed, there is no need for the interface to be Up.
1258 *
2865d42c
LF
1259 */
1260static int r8711_wx_set_essid(struct net_device *dev,
1261 struct iw_request_info *a,
1262 union iwreq_data *wrqu, char *extra)
1263{
7c1f4203 1264 struct _adapter *padapter = (struct _adapter *)netdev_priv(dev);
2865d42c
LF
1265 struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
1266 struct __queue *queue = &pmlmepriv->scanned_queue;
1267 struct wlan_network *pnetwork = NULL;
1268 enum NDIS_802_11_AUTHENTICATION_MODE authmode;
1269 struct ndis_802_11_ssid ndis_ssid;
1270 u8 *dst_ssid, *src_ssid;
1271 struct list_head *phead;
1272 u32 len;
1273
2865d42c 1274 if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY))
2192e606 1275 return -EBUSY;
2865d42c
LF
1276 if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING))
1277 return 0;
1278 if (wrqu->essid.length > IW_ESSID_MAX_SIZE)
1279 return -E2BIG;
1280 authmode = padapter->securitypriv.ndisauthtype;
1281 if (wrqu->essid.flags && wrqu->essid.length) {
1282 len = (wrqu->essid.length < IW_ESSID_MAX_SIZE) ?
1283 wrqu->essid.length : IW_ESSID_MAX_SIZE;
1284 memset(&ndis_ssid, 0, sizeof(struct ndis_802_11_ssid));
1285 ndis_ssid.SsidLength = len;
1286 memcpy(ndis_ssid.Ssid, extra, len);
1287 src_ssid = ndis_ssid.Ssid;
e99a428a 1288 phead = &queue->queue;
849fb0a8 1289 pmlmepriv->pscanned = phead->next;
2865d42c
LF
1290 while (1) {
1291 if (end_of_queue_search(phead, pmlmepriv->pscanned))
1292 break;
1293 pnetwork = LIST_CONTAINOR(pmlmepriv->pscanned,
1294 struct wlan_network, list);
849fb0a8 1295 pmlmepriv->pscanned = pmlmepriv->pscanned->next;
2865d42c
LF
1296 dst_ssid = pnetwork->network.Ssid.Ssid;
1297 if ((!memcmp(dst_ssid, src_ssid, ndis_ssid.SsidLength))
1298 && (pnetwork->network.Ssid.SsidLength ==
1299 ndis_ssid.SsidLength)) {
c6dc001f
AB
1300 if (check_fwstate(pmlmepriv,
1301 WIFI_ADHOC_STATE)) {
1302 if (pnetwork->network.
1303 InfrastructureMode
1304 !=
1305 padapter->mlmepriv.
1306 cur_network.network.
1307 InfrastructureMode)
1308 continue;
1309 }
1310
2192e606 1311 r8712_set_802_11_infrastructure_mode(
2865d42c 1312 padapter,
2192e606 1313 pnetwork->network.InfrastructureMode);
2865d42c
LF
1314 break;
1315 }
1316 }
1317 r8712_set_802_11_authentication_mode(padapter, authmode);
1318 r8712_set_802_11_ssid(padapter, &ndis_ssid);
1319 }
1320 return -EINPROGRESS;
1321}
1322
1323static int r8711_wx_get_essid(struct net_device *dev,
1324 struct iw_request_info *a,
1325 union iwreq_data *wrqu, char *extra)
1326{
7c1f4203 1327 struct _adapter *padapter = (struct _adapter *)netdev_priv(dev);
2865d42c
LF
1328 struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
1329 struct ndis_wlan_bssid_ex *pcur_bss = &pmlmepriv->cur_network.network;
1330 u32 len, ret = 0;
1331
1332 if (check_fwstate(pmlmepriv, _FW_LINKED|WIFI_ADHOC_MASTER_STATE)) {
1333 len = pcur_bss->Ssid.SsidLength;
1334 wrqu->essid.length = len;
1335 memcpy(extra, pcur_bss->Ssid.Ssid, len);
1336 wrqu->essid.flags = 1;
2192e606
AB
1337 } else {
1338 ret = -ENOLINK;
1339 }
2865d42c
LF
1340 return ret;
1341}
1342
1343static int r8711_wx_set_rate(struct net_device *dev,
1344 struct iw_request_info *a,
1345 union iwreq_data *wrqu, char *extra)
1346{
7c1f4203 1347 struct _adapter *padapter = (struct _adapter *)netdev_priv(dev);
2865d42c
LF
1348 u32 target_rate = wrqu->bitrate.value;
1349 u32 fixed = wrqu->bitrate.fixed;
1350 u32 ratevalue = 0;
1351 u8 datarates[NumRates];
1352 u8 mpdatarate[NumRates] = {11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0xff};
1353 int i, ret = 0;
1354
1355 if (target_rate == -1) {
1356 ratevalue = 11;
1357 goto set_rate;
1358 }
1359 target_rate = target_rate / 100000;
1360 switch (target_rate) {
1361 case 10:
1362 ratevalue = 0;
1363 break;
1364 case 20:
1365 ratevalue = 1;
1366 break;
1367 case 55:
1368 ratevalue = 2;
1369 break;
1370 case 60:
1371 ratevalue = 3;
1372 break;
1373 case 90:
1374 ratevalue = 4;
1375 break;
1376 case 110:
1377 ratevalue = 5;
1378 break;
1379 case 120:
1380 ratevalue = 6;
1381 break;
1382 case 180:
1383 ratevalue = 7;
1384 break;
1385 case 240:
1386 ratevalue = 8;
1387 break;
1388 case 360:
1389 ratevalue = 9;
1390 break;
1391 case 480:
1392 ratevalue = 10;
1393 break;
1394 case 540:
1395 ratevalue = 11;
1396 break;
1397 default:
1398 ratevalue = 11;
1399 break;
1400 }
1401set_rate:
1402 for (i = 0; i < NumRates; i++) {
1403 if (ratevalue == mpdatarate[i]) {
1404 datarates[i] = mpdatarate[i];
1405 if (fixed == 0)
1406 break;
1407 } else
1408 datarates[i] = 0xff;
1409 }
1410 if (r8712_setdatarate_cmd(padapter, datarates) != _SUCCESS)
2192e606 1411 ret = -ENOMEM;
2865d42c
LF
1412 return ret;
1413}
1414
1415static int r8711_wx_get_rate(struct net_device *dev,
1416 struct iw_request_info *info,
1417 union iwreq_data *wrqu, char *extra)
1418{
7c1f4203 1419 struct _adapter *padapter = (struct _adapter *)netdev_priv(dev);
2865d42c
LF
1420 struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
1421 struct ndis_wlan_bssid_ex *pcur_bss = &pmlmepriv->cur_network.network;
1422 struct ieee80211_ht_cap *pht_capie;
c6dc001f 1423 unsigned char rf_type = padapter->registrypriv.rf_config;
2865d42c
LF
1424 int i;
1425 u8 *p;
1426 u16 rate, max_rate = 0, ht_cap = false;
1427 u32 ht_ielen = 0;
1428 u8 bw_40MHz = 0, short_GI = 0;
1429 u16 mcs_rate = 0;
1430
1431 i = 0;
1432 if (check_fwstate(pmlmepriv, _FW_LINKED|WIFI_ADHOC_MASTER_STATE)) {
1433 p = r8712_get_ie(&pcur_bss->IEs[12],
1434 _HT_CAPABILITY_IE_, &ht_ielen,
1435 pcur_bss->IELength - 12);
1436 if (p && ht_ielen > 0) {
1437 ht_cap = true;
1438 pht_capie = (struct ieee80211_ht_cap *)(p + 2);
0636b460 1439 memcpy(&mcs_rate, pht_capie->supp_mcs_set, 2);
2865d42c
LF
1440 bw_40MHz = (pht_capie->cap_info &
1441 IEEE80211_HT_CAP_SUP_WIDTH) ? 1 : 0;
1442 short_GI = (pht_capie->cap_info &
1443 (IEEE80211_HT_CAP_SGI_20 |
1444 IEEE80211_HT_CAP_SGI_40)) ? 1 : 0;
1445 }
1446 while ((pcur_bss->SupportedRates[i] != 0) &&
1447 (pcur_bss->SupportedRates[i] != 0xFF)) {
1448 rate = pcur_bss->SupportedRates[i] & 0x7F;
1449 if (rate > max_rate)
1450 max_rate = rate;
1451 wrqu->bitrate.fixed = 0; /* no auto select */
1452 wrqu->bitrate.value = rate*500000;
1453 i++;
1454 }
1455 if (ht_cap == true) {
c6dc001f
AB
1456 if (mcs_rate & 0x8000 /* MCS15 */
1457 &&
1458 RTL8712_RF_2T2R == rf_type)
2865d42c
LF
1459 max_rate = (bw_40MHz) ? ((short_GI) ? 300 :
1460 270) : ((short_GI) ? 144 : 130);
2865d42c
LF
1461 else /* default MCS7 */
1462 max_rate = (bw_40MHz) ? ((short_GI) ? 150 :
1463 135) : ((short_GI) ? 72 : 65);
1464 max_rate *= 2; /* Mbps/2 */
2865d42c 1465 }
3ae70746 1466 wrqu->bitrate.value = max_rate * 500000;
2865d42c 1467 } else
2192e606 1468 return -ENOLINK;
2865d42c
LF
1469 return 0;
1470}
1471
1472static int r8711_wx_get_rts(struct net_device *dev,
1473 struct iw_request_info *info,
1474 union iwreq_data *wrqu, char *extra)
1475{
7c1f4203 1476 struct _adapter *padapter = (struct _adapter *)netdev_priv(dev);
2865d42c
LF
1477
1478 wrqu->rts.value = padapter->registrypriv.rts_thresh;
1479 wrqu->rts.fixed = 0; /* no auto select */
1480 return 0;
1481}
1482
1483static int r8711_wx_set_frag(struct net_device *dev,
1484 struct iw_request_info *info,
1485 union iwreq_data *wrqu, char *extra)
1486{
7c1f4203 1487 struct _adapter *padapter = (struct _adapter *)netdev_priv(dev);
2865d42c
LF
1488
1489 if (wrqu->frag.disabled)
1490 padapter->xmitpriv.frag_len = MAX_FRAG_THRESHOLD;
1491 else {
1492 if (wrqu->frag.value < MIN_FRAG_THRESHOLD ||
1493 wrqu->frag.value > MAX_FRAG_THRESHOLD)
1494 return -EINVAL;
1495 padapter->xmitpriv.frag_len = wrqu->frag.value & ~0x1;
1496 }
1497 return 0;
1498}
1499
1500static int r8711_wx_get_frag(struct net_device *dev,
1501 struct iw_request_info *info,
1502 union iwreq_data *wrqu, char *extra)
1503{
7c1f4203 1504 struct _adapter *padapter = (struct _adapter *) netdev_priv(dev);
2865d42c
LF
1505
1506 wrqu->frag.value = padapter->xmitpriv.frag_len;
1507 wrqu->frag.fixed = 0; /* no auto select */
1508 return 0;
1509}
1510
1511static int r8711_wx_get_retry(struct net_device *dev,
1512 struct iw_request_info *info,
1513 union iwreq_data *wrqu, char *extra)
1514{
1515 wrqu->retry.value = 7;
1516 wrqu->retry.fixed = 0; /* no auto select */
1517 wrqu->retry.disabled = 1;
1518 return 0;
1519}
1520
1521static int r8711_wx_set_enc(struct net_device *dev,
1522 struct iw_request_info *info,
1523 union iwreq_data *wrqu, char *keybuf)
1524{
1525 u32 key;
1526 u32 keyindex_provided;
1527 struct NDIS_802_11_WEP wep;
1528 enum NDIS_802_11_AUTHENTICATION_MODE authmode;
1529 struct iw_point *erq = &(wrqu->encoding);
7c1f4203 1530 struct _adapter *padapter = (struct _adapter *) netdev_priv(dev);
2865d42c
LF
1531
1532 key = erq->flags & IW_ENCODE_INDEX;
1533 memset(&wep, 0, sizeof(struct NDIS_802_11_WEP));
1534 if (erq->flags & IW_ENCODE_DISABLED) {
87a573ad 1535 netdev_info(dev, "r8712u: %s: EncryptionDisabled\n", __func__);
2865d42c
LF
1536 padapter->securitypriv.ndisencryptstatus =
1537 Ndis802_11EncryptionDisabled;
1538 padapter->securitypriv.PrivacyAlgrthm = _NO_PRIVACY_;
1539 padapter->securitypriv.XGrpPrivacy = _NO_PRIVACY_;
1540 padapter->securitypriv.AuthAlgrthm = 0; /* open system */
1541 authmode = Ndis802_11AuthModeOpen;
1542 padapter->securitypriv.ndisauthtype = authmode;
1543 return 0;
1544 }
1545 if (key) {
1546 if (key > WEP_KEYS)
1547 return -EINVAL;
1548 key--;
1549 keyindex_provided = 1;
1550 } else {
1551 keyindex_provided = 0;
1552 key = padapter->securitypriv.PrivacyKeyIndex;
1553 }
1554 /* set authentication mode */
1555 if (erq->flags & IW_ENCODE_OPEN) {
87a573ad 1556 netdev_info(dev, "r8712u: %s: IW_ENCODE_OPEN\n", __func__);
2865d42c
LF
1557 padapter->securitypriv.ndisencryptstatus =
1558 Ndis802_11Encryption1Enabled;
1559 padapter->securitypriv.AuthAlgrthm = 0; /* open system */
1560 padapter->securitypriv.PrivacyAlgrthm = _NO_PRIVACY_;
1561 padapter->securitypriv.XGrpPrivacy = _NO_PRIVACY_;
1562 authmode = Ndis802_11AuthModeOpen;
1563 padapter->securitypriv.ndisauthtype = authmode;
1564 } else if (erq->flags & IW_ENCODE_RESTRICTED) {
57b6686e
TP
1565 netdev_info(dev,
1566 "r8712u: %s: IW_ENCODE_RESTRICTED\n", __func__);
2865d42c
LF
1567 padapter->securitypriv.ndisencryptstatus =
1568 Ndis802_11Encryption1Enabled;
1569 padapter->securitypriv.AuthAlgrthm = 1; /* shared system */
1570 padapter->securitypriv.PrivacyAlgrthm = _WEP40_;
1571 padapter->securitypriv.XGrpPrivacy = _WEP40_;
1572 authmode = Ndis802_11AuthModeShared;
1573 padapter->securitypriv.ndisauthtype = authmode;
1574 } else {
1575 padapter->securitypriv.ndisencryptstatus =
1576 Ndis802_11Encryption1Enabled;
1577 padapter->securitypriv.AuthAlgrthm = 0; /* open system */
1578 padapter->securitypriv.PrivacyAlgrthm = _NO_PRIVACY_;
1579 padapter->securitypriv.XGrpPrivacy = _NO_PRIVACY_;
1580 authmode = Ndis802_11AuthModeOpen;
1581 padapter->securitypriv.ndisauthtype = authmode;
1582 }
1583 wep.KeyIndex = key;
1584 if (erq->length > 0) {
1585 wep.KeyLength = erq->length <= 5 ? 5 : 13;
1586 wep.Length = wep.KeyLength +
1587 FIELD_OFFSET(struct NDIS_802_11_WEP, KeyMaterial);
1588 } else {
77e73e8c 1589 wep.KeyLength = 0;
2865d42c
LF
1590 if (keyindex_provided == 1) { /* set key_id only, no given
1591 * KeyMaterial(erq->length==0).*/
1592 padapter->securitypriv.PrivacyKeyIndex = key;
1593 switch (padapter->securitypriv.DefKeylen[key]) {
1594 case 5:
1595 padapter->securitypriv.PrivacyAlgrthm =
1596 _WEP40_;
1597 break;
1598 case 13:
1599 padapter->securitypriv.PrivacyAlgrthm =
1600 _WEP104_;
1601 break;
1602 default:
1603 padapter->securitypriv.PrivacyAlgrthm =
1604 _NO_PRIVACY_;
1605 break;
1606 }
1607 return 0;
1608 }
1609 }
1610 wep.KeyIndex |= 0x80000000; /* transmit key */
1611 memcpy(wep.KeyMaterial, keybuf, wep.KeyLength);
1612 if (r8712_set_802_11_add_wep(padapter, &wep) == _FAIL)
1613 return -EOPNOTSUPP;
1614 return 0;
1615}
1616
1617static int r8711_wx_get_enc(struct net_device *dev,
1618 struct iw_request_info *info,
1619 union iwreq_data *wrqu, char *keybuf)
1620{
1621 uint key, ret = 0;
7c1f4203 1622 struct _adapter *padapter = (struct _adapter *) netdev_priv(dev);
2865d42c
LF
1623 struct iw_point *erq = &(wrqu->encoding);
1624 struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
1625
1626 if (check_fwstate(pmlmepriv, _FW_LINKED) == false) {
1627 if (!check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) {
1628 erq->length = 0;
1629 erq->flags |= IW_ENCODE_DISABLED;
1630 return 0;
1631 }
1632 }
1633 key = erq->flags & IW_ENCODE_INDEX;
1634 if (key) {
1635 if (key > WEP_KEYS)
1636 return -EINVAL;
1637 key--;
1638 } else {
1639 key = padapter->securitypriv.PrivacyKeyIndex;
1640 }
1641 erq->flags = key + 1;
1642 switch (padapter->securitypriv.ndisencryptstatus) {
1643 case Ndis802_11EncryptionNotSupported:
1644 case Ndis802_11EncryptionDisabled:
1645 erq->length = 0;
1646 erq->flags |= IW_ENCODE_DISABLED;
1647 break;
1648 case Ndis802_11Encryption1Enabled:
1649 erq->length = padapter->securitypriv.DefKeylen[key];
1650 if (erq->length) {
1651 memcpy(keybuf, padapter->securitypriv.DefKey[
1652 key].skey, padapter->securitypriv.
1653 DefKeylen[key]);
1654 erq->flags |= IW_ENCODE_ENABLED;
1655 if (padapter->securitypriv.ndisauthtype ==
1656 Ndis802_11AuthModeOpen)
1657 erq->flags |= IW_ENCODE_OPEN;
1658 else if (padapter->securitypriv.ndisauthtype ==
1659 Ndis802_11AuthModeShared)
1660 erq->flags |= IW_ENCODE_RESTRICTED;
1661 } else {
1662 erq->length = 0;
1663 erq->flags |= IW_ENCODE_DISABLED;
1664 }
1665 break;
1666 case Ndis802_11Encryption2Enabled:
1667 case Ndis802_11Encryption3Enabled:
1668 erq->length = 16;
1669 erq->flags |= (IW_ENCODE_ENABLED | IW_ENCODE_OPEN |
1670 IW_ENCODE_NOKEY);
1671 break;
1672 default:
1673 erq->length = 0;
1674 erq->flags |= IW_ENCODE_DISABLED;
1675 break;
1676 }
1677 return ret;
1678}
1679
1680static int r8711_wx_get_power(struct net_device *dev,
1681 struct iw_request_info *info,
1682 union iwreq_data *wrqu, char *extra)
1683{
1684 wrqu->power.value = 0;
1685 wrqu->power.fixed = 0; /* no auto select */
1686 wrqu->power.disabled = 1;
1687 return 0;
1688}
1689
1690static int r871x_wx_set_gen_ie(struct net_device *dev,
1691 struct iw_request_info *info,
1692 union iwreq_data *wrqu, char *extra)
1693{
7c1f4203 1694 struct _adapter *padapter = (struct _adapter *)netdev_priv(dev);
2865d42c
LF
1695
1696 return r871x_set_wpa_ie(padapter, extra, wrqu->data.length);
1697}
1698
1699static int r871x_wx_set_auth(struct net_device *dev,
1700 struct iw_request_info *info,
1701 union iwreq_data *wrqu, char *extra)
1702{
7c1f4203 1703 struct _adapter *padapter = (struct _adapter *)netdev_priv(dev);
2865d42c
LF
1704 struct iw_param *param = (struct iw_param *)&(wrqu->param);
1705 int paramid;
1706 int paramval;
1707 int ret = 0;
1708
1709 paramid = param->flags & IW_AUTH_INDEX;
1710 paramval = param->value;
1711 switch (paramid) {
1712 case IW_AUTH_WPA_VERSION:
1713 break;
1714 case IW_AUTH_CIPHER_PAIRWISE:
1715 break;
1716 case IW_AUTH_CIPHER_GROUP:
1717 break;
1718 case IW_AUTH_KEY_MGMT:
1719 /*
1720 * ??? does not use these parameters
1721 */
1722 break;
1723 case IW_AUTH_TKIP_COUNTERMEASURES:
1724 if (paramval) {
1725 /* wpa_supplicant is enabling tkip countermeasure. */
1726 padapter->securitypriv.btkip_countermeasure = true;
1727 } else {
1728 /* wpa_supplicant is disabling tkip countermeasure. */
1729 padapter->securitypriv.btkip_countermeasure = false;
1730 }
1731 break;
1732 case IW_AUTH_DROP_UNENCRYPTED:
1733 /* HACK:
1734 *
1735 * wpa_supplicant calls set_wpa_enabled when the driver
1736 * is loaded and unloaded, regardless of if WPA is being
1737 * used. No other calls are made which can be used to
1738 * determine if encryption will be used or not prior to
1739 * association being expected. If encryption is not being
1740 * used, drop_unencrypted is set to false, else true -- we
1741 * can use this to determine if the CAP_PRIVACY_ON bit should
1742 * be set.
1743 */
1744 if (padapter->securitypriv.ndisencryptstatus ==
1745 Ndis802_11Encryption1Enabled) {
1746 /* it means init value, or using wep,
1747 * ndisencryptstatus =
1748 * Ndis802_11Encryption1Enabled,
1749 * then it needn't reset it;
1750 */
1751 break;
1752 }
1753
1754 if (paramval) {
1755 padapter->securitypriv.ndisencryptstatus =
1756 Ndis802_11EncryptionDisabled;
1757 padapter->securitypriv.PrivacyAlgrthm =
1758 _NO_PRIVACY_;
1759 padapter->securitypriv.XGrpPrivacy =
1760 _NO_PRIVACY_;
1761 padapter->securitypriv.AuthAlgrthm = 0;
1762 padapter->securitypriv.ndisauthtype =
1763 Ndis802_11AuthModeOpen;
1764 }
1765 break;
1766 case IW_AUTH_80211_AUTH_ALG:
1767 ret = wpa_set_auth_algs(dev, (u32)paramval);
1768 break;
1769 case IW_AUTH_WPA_ENABLED:
1770 break;
1771 case IW_AUTH_RX_UNENCRYPTED_EAPOL:
1772 break;
1773 case IW_AUTH_PRIVACY_INVOKED:
1774 break;
1775 default:
1776 return -EOPNOTSUPP;
1777 }
1778
1779 return ret;
1780}
1781
1782static int r871x_wx_set_enc_ext(struct net_device *dev,
1783 struct iw_request_info *info,
1784 union iwreq_data *wrqu, char *extra)
1785{
1786 struct iw_point *pencoding = &wrqu->encoding;
1787 struct iw_encode_ext *pext = (struct iw_encode_ext *)extra;
1788 struct ieee_param *param = NULL;
1789 char *alg_name;
1790 u32 param_len;
1791 int ret = 0;
1792
2865d42c
LF
1793 switch (pext->alg) {
1794 case IW_ENCODE_ALG_NONE:
1795 alg_name = "none";
1796 break;
1797 case IW_ENCODE_ALG_WEP:
1798 alg_name = "WEP";
1799 break;
1800 case IW_ENCODE_ALG_TKIP:
1801 alg_name = "TKIP";
1802 break;
1803 case IW_ENCODE_ALG_CCMP:
1804 alg_name = "CCMP";
1805 break;
1806 default:
2192e606 1807 return -EINVAL;
2865d42c 1808 }
55d4f6cc
CE
1809
1810 param_len = sizeof(struct ieee_param) + pext->key_len;
91d435fe 1811 param = kzalloc(param_len, GFP_ATOMIC);
55d4f6cc
CE
1812 if (param == NULL)
1813 return -ENOMEM;
55d4f6cc
CE
1814 param->cmd = IEEE_CMD_SET_ENCRYPTION;
1815 memset(param->sta_addr, 0xff, ETH_ALEN);
1816
2865d42c
LF
1817 strncpy((char *)param->u.crypt.alg, alg_name, IEEE_CRYPT_ALG_NAME_LEN);
1818 if (pext->ext_flags & IW_ENCODE_EXT_GROUP_KEY)
1819 param->u.crypt.set_tx = 0;
1820 if (pext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)
1821 param->u.crypt.set_tx = 1;
1822 param->u.crypt.idx = (pencoding->flags & 0x00FF) - 1;
1823 if (pext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID)
1824 memcpy(param->u.crypt.seq, pext->rx_seq, 8);
1825 if (pext->key_len) {
1826 param->u.crypt.key_len = pext->key_len;
1827 memcpy(param + 1, pext + 1, pext->key_len);
1828 }
1829 ret = wpa_set_encryption(dev, param, param_len);
40083865 1830 kfree(param);
2865d42c
LF
1831 return ret;
1832}
1833
1834static int r871x_wx_get_nick(struct net_device *dev,
1835 struct iw_request_info *info,
1836 union iwreq_data *wrqu, char *extra)
1837{
1838 if (extra) {
1839 wrqu->data.length = 8;
1840 wrqu->data.flags = 1;
1841 memcpy(extra, "rtl_wifi", 8);
1842 }
1843 return 0;
1844}
1845
1846static int r8711_wx_read32(struct net_device *dev,
1847 struct iw_request_info *info,
1848 union iwreq_data *wrqu, char *keybuf)
1849{
7c1f4203 1850 struct _adapter *padapter = (struct _adapter *) netdev_priv(dev);
2865d42c
LF
1851 u32 addr;
1852 u32 data32;
1853
1854 get_user(addr, (u32 __user *)wrqu->data.pointer);
1855 data32 = r8712_read32(padapter, addr);
1856 put_user(data32, (u32 __user *)wrqu->data.pointer);
1857 wrqu->data.length = (data32 & 0xffff0000) >> 16;
1858 wrqu->data.flags = data32 & 0xffff;
1859 get_user(addr, (u32 __user *)wrqu->data.pointer);
1860 return 0;
1861}
1862
1863static int r8711_wx_write32(struct net_device *dev,
1864 struct iw_request_info *info,
1865 union iwreq_data *wrqu, char *keybuf)
1866{
7c1f4203 1867 struct _adapter *padapter = (struct _adapter *) netdev_priv(dev);
2865d42c
LF
1868 u32 addr;
1869 u32 data32;
1870
1871 get_user(addr, (u32 __user *)wrqu->data.pointer);
77e73e8c 1872 data32 = ((u32)wrqu->data.length<<16) | (u32)wrqu->data.flags;
2865d42c
LF
1873 r8712_write32(padapter, addr, data32);
1874 return 0;
1875}
1876
1877static int dummy(struct net_device *dev,
1878 struct iw_request_info *a,
1879 union iwreq_data *wrqu, char *b)
1880{
2192e606 1881 return -ENOSYS;
2865d42c
LF
1882}
1883
1884static int r8711_drvext_hdl(struct net_device *dev,
1885 struct iw_request_info *info,
1886 union iwreq_data *wrqu, char *extra)
1887{
1888 return 0;
1889}
1890
1891static int r871x_mp_ioctl_hdl(struct net_device *dev,
1892 struct iw_request_info *info,
1893 union iwreq_data *wrqu, char *extra)
1894{
7c1f4203 1895 struct _adapter *padapter = (struct _adapter *)netdev_priv(dev);
2865d42c
LF
1896 struct iw_point *p = &wrqu->data;
1897 struct oid_par_priv oid_par;
1898 struct mp_ioctl_handler *phandler;
1899 struct mp_ioctl_param *poidparam;
1900 unsigned long BytesRead, BytesWritten, BytesNeeded;
1901 u8 *pparmbuf = NULL, bset;
1902 u16 len;
1903 uint status;
1904 int ret = 0;
1905
1906 if ((!p->length) || (!p->pointer)) {
1907 ret = -EINVAL;
1908 goto _r871x_mp_ioctl_hdl_exit;
1909 }
1910 bset = (u8)(p->flags & 0xFFFF);
1911 len = p->length;
1912 pparmbuf = NULL;
91d435fe 1913 pparmbuf = kmalloc(len, GFP_ATOMIC);
2865d42c
LF
1914 if (pparmbuf == NULL) {
1915 ret = -ENOMEM;
1916 goto _r871x_mp_ioctl_hdl_exit;
1917 }
1918 if (copy_from_user(pparmbuf, p->pointer, len)) {
1919 ret = -EFAULT;
1920 goto _r871x_mp_ioctl_hdl_exit;
1921 }
1922 poidparam = (struct mp_ioctl_param *)pparmbuf;
1923 if (poidparam->subcode >= MAX_MP_IOCTL_SUBCODE) {
1924 ret = -EINVAL;
1925 goto _r871x_mp_ioctl_hdl_exit;
1926 }
1927 phandler = mp_ioctl_hdl + poidparam->subcode;
1928 if ((phandler->paramsize != 0) &&
1929 (poidparam->len < phandler->paramsize)) {
1930 ret = -EINVAL;
1931 goto _r871x_mp_ioctl_hdl_exit;
1932 }
1933 if (phandler->oid == 0 && phandler->handler)
1934 status = phandler->handler(&oid_par);
1935 else if (phandler->handler) {
1936 oid_par.adapter_context = padapter;
1937 oid_par.oid = phandler->oid;
1938 oid_par.information_buf = poidparam->data;
1939 oid_par.information_buf_len = poidparam->len;
1940 oid_par.dbg = 0;
1941 BytesWritten = 0;
1942 BytesNeeded = 0;
1943 if (bset) {
1944 oid_par.bytes_rw = &BytesRead;
1945 oid_par.bytes_needed = &BytesNeeded;
1946 oid_par.type_of_oid = SET_OID;
1947 } else {
1948 oid_par.bytes_rw = &BytesWritten;
1949 oid_par.bytes_needed = &BytesNeeded;
1950 oid_par.type_of_oid = QUERY_OID;
1951 }
1952 status = phandler->handler(&oid_par);
1953 /* todo:check status, BytesNeeded, etc. */
1954 } else {
87a573ad
PF
1955 netdev_info(dev, "r8712u: %s: err!, subcode=%d, oid=%d, handler=%p\n",
1956 __func__, poidparam->subcode, phandler->oid,
1957 phandler->handler);
2865d42c
LF
1958 ret = -EFAULT;
1959 goto _r871x_mp_ioctl_hdl_exit;
1960 }
1961 if (bset == 0x00) { /* query info */
1962 if (copy_to_user(p->pointer, pparmbuf, len))
1963 ret = -EFAULT;
1964 }
1965 if (status) {
1966 ret = -EFAULT;
1967 goto _r871x_mp_ioctl_hdl_exit;
1968 }
1969_r871x_mp_ioctl_hdl_exit:
b7977fa2 1970 kfree(pparmbuf);
2865d42c
LF
1971 return ret;
1972}
1973
1974static int r871x_get_ap_info(struct net_device *dev,
1975 struct iw_request_info *info,
1976 union iwreq_data *wrqu, char *extra)
1977{
7c1f4203 1978 struct _adapter *padapter = (struct _adapter *)netdev_priv(dev);
2865d42c
LF
1979 struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
1980 struct __queue *queue = &pmlmepriv->scanned_queue;
1981 struct iw_point *pdata = &wrqu->data;
1982 struct wlan_network *pnetwork = NULL;
1983 u32 cnt = 0, wpa_ielen;
1984 unsigned long irqL;
1985 struct list_head *plist, *phead;
1986 unsigned char *pbuf;
1987 u8 bssid[ETH_ALEN];
1988 char data[32];
1989
1990 if (padapter->bDriverStopped || (pdata == NULL))
1991 return -EINVAL;
1992 while (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY|_FW_UNDER_LINKING)) {
1993 msleep(30);
1994 cnt++;
1995 if (cnt > 100)
1996 break;
1997 }
1998 pdata->flags = 0;
1999 if (pdata->length >= 32) {
2000 if (copy_from_user(data, pdata->pointer, 32))
2001 return -EINVAL;
2002 } else
2003 return -EINVAL;
2004 spin_lock_irqsave(&(pmlmepriv->scanned_queue.lock), irqL);
e99a428a 2005 phead = &queue->queue;
849fb0a8 2006 plist = phead->next;
2865d42c
LF
2007 while (1) {
2008 if (end_of_queue_search(phead, plist) == true)
2009 break;
2010 pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
2011 if (hwaddr_aton_i(data, bssid)) {
87a573ad
PF
2012 netdev_info(dev, "r8712u: Invalid BSSID '%s'.\n",
2013 (u8 *)data);
2865d42c 2014 spin_unlock_irqrestore(&(pmlmepriv->scanned_queue.lock),
87a573ad 2015 irqL);
2865d42c
LF
2016 return -EINVAL;
2017 }
87a573ad 2018 netdev_info(dev, "r8712u: BSSID:%pM\n", bssid);
2865d42c
LF
2019 if (!memcmp(bssid, pnetwork->network.MacAddress, ETH_ALEN)) {
2020 /* BSSID match, then check if supporting wpa/wpa2 */
2021 pbuf = r8712_get_wpa_ie(&pnetwork->network.IEs[12],
2022 &wpa_ielen, pnetwork->network.IELength-12);
2023 if (pbuf && (wpa_ielen > 0)) {
2024 pdata->flags = 1;
2025 break;
2026 }
2027 pbuf = r8712_get_wpa2_ie(&pnetwork->network.IEs[12],
2028 &wpa_ielen, pnetwork->network.IELength-12);
2029 if (pbuf && (wpa_ielen > 0)) {
2030 pdata->flags = 2;
2031 break;
2032 }
2033 }
849fb0a8 2034 plist = plist->next;
2865d42c
LF
2035 }
2036 spin_unlock_irqrestore(&(pmlmepriv->scanned_queue.lock), irqL);
2037 if (pdata->length >= 34) {
2038 if (copy_to_user((u8 __user *)pdata->pointer + 32,
2039 (u8 *)&pdata->flags, 1))
2040 return -EINVAL;
2041 }
2042 return 0;
2043}
2044
2045static int r871x_set_pid(struct net_device *dev,
2046 struct iw_request_info *info,
2047 union iwreq_data *wrqu, char *extra)
2048{
7c1f4203 2049 struct _adapter *padapter = (struct _adapter *) netdev_priv(dev);
2865d42c
LF
2050 struct iw_point *pdata = &wrqu->data;
2051
2052 if ((padapter->bDriverStopped) || (pdata == NULL))
2053 return -EINVAL;
2054 if (copy_from_user(&padapter->pid, pdata->pointer, sizeof(int)))
2055 return -EINVAL;
2056 return 0;
2057}
2058
c6dc001f
AB
2059static int r871x_set_chplan(struct net_device *dev,
2060 struct iw_request_info *info,
2061 union iwreq_data *wrqu, char *extra)
2062{
2063 int ret = 0;
2064 struct _adapter *padapter = (struct _adapter *) netdev_priv(dev);
2065 struct iw_point *pdata = &wrqu->data;
2066 int ch_plan = -1;
2067
2068 if ((padapter->bDriverStopped) || (pdata == NULL)) {
2069 ret = -EINVAL;
2070 goto exit;
2071 }
2072 ch_plan = (int)*extra;
2073 r8712_set_chplan_cmd(padapter, ch_plan);
2074
2075exit:
2076
2077 return ret;
2078}
2079
2865d42c
LF
2080static int r871x_wps_start(struct net_device *dev,
2081 struct iw_request_info *info,
2082 union iwreq_data *wrqu, char *extra)
2083{
7c1f4203 2084 struct _adapter *padapter = (struct _adapter *)netdev_priv(dev);
2865d42c
LF
2085 struct iw_point *pdata = &wrqu->data;
2086 u32 u32wps_start = 0;
2865d42c 2087
2865d42c
LF
2088 if ((padapter->bDriverStopped) || (pdata == NULL))
2089 return -EINVAL;
605fba82
WY
2090 if (copy_from_user((void *)&u32wps_start, pdata->pointer, 4))
2091 return -EFAULT;
2865d42c
LF
2092 if (u32wps_start == 0)
2093 u32wps_start = *extra;
2094 if (u32wps_start == 1) /* WPS Start */
2095 padapter->ledpriv.LedControlHandler(padapter,
2096 LED_CTL_START_WPS);
2097 else if (u32wps_start == 2) /* WPS Stop because of wps success */
2098 padapter->ledpriv.LedControlHandler(padapter,
2099 LED_CTL_STOP_WPS);
2100 else if (u32wps_start == 3) /* WPS Stop because of wps fail */
2101 padapter->ledpriv.LedControlHandler(padapter,
2102 LED_CTL_STOP_WPS_FAIL);
2103 return 0;
2104}
2105
2106static int wpa_set_param(struct net_device *dev, u8 name, u32 value)
2107{
7c1f4203 2108 struct _adapter *padapter = (struct _adapter *) netdev_priv(dev);
2865d42c
LF
2109
2110 switch (name) {
2111 case IEEE_PARAM_WPA_ENABLED:
2112 padapter->securitypriv.AuthAlgrthm = 2; /* 802.1x */
2113 switch ((value)&0xff) {
2114 case 1: /* WPA */
2115 padapter->securitypriv.ndisauthtype =
2116 Ndis802_11AuthModeWPAPSK; /* WPA_PSK */
2117 padapter->securitypriv.ndisencryptstatus =
2118 Ndis802_11Encryption2Enabled;
2119 break;
2120 case 2: /* WPA2 */
2121 padapter->securitypriv.ndisauthtype =
2122 Ndis802_11AuthModeWPA2PSK; /* WPA2_PSK */
2123 padapter->securitypriv.ndisencryptstatus =
2124 Ndis802_11Encryption3Enabled;
2125 break;
2126 }
2127 break;
2128 case IEEE_PARAM_TKIP_COUNTERMEASURES:
2129 break;
2130 case IEEE_PARAM_DROP_UNENCRYPTED:
2131 /* HACK:
2132 *
2133 * wpa_supplicant calls set_wpa_enabled when the driver
2134 * is loaded and unloaded, regardless of if WPA is being
2135 * used. No other calls are made which can be used to
2136 * determine if encryption will be used or not prior to
2137 * association being expected. If encryption is not being
2138 * used, drop_unencrypted is set to false, else true -- we
2139 * can use this to determine if the CAP_PRIVACY_ON bit should
2140 * be set.
2141 */
2142 break;
2143 case IEEE_PARAM_PRIVACY_INVOKED:
2144 break;
2145 case IEEE_PARAM_AUTH_ALGS:
2146 return wpa_set_auth_algs(dev, value);
2865d42c
LF
2147 case IEEE_PARAM_IEEE_802_1X:
2148 break;
2149 case IEEE_PARAM_WPAX_SELECT:
2150 /* added for WPA2 mixed mode */
2151 break;
2152 default:
2153 return -EOPNOTSUPP;
2154 }
2155 return 0;
2156}
2157
2158static int wpa_mlme(struct net_device *dev, u32 command, u32 reason)
2159{
7c1f4203 2160 struct _adapter *padapter = (struct _adapter *) netdev_priv(dev);
2865d42c
LF
2161
2162 switch (command) {
2163 case IEEE_MLME_STA_DEAUTH:
2164 if (!r8712_set_802_11_disassociate(padapter))
2165 return -1;
2166 break;
2167 case IEEE_MLME_STA_DISASSOC:
2168 if (!r8712_set_802_11_disassociate(padapter))
2169 return -1;
2170 break;
2171 default:
2172 return -EOPNOTSUPP;
2173 }
2174 return 0;
2175}
2176
2177static int wpa_supplicant_ioctl(struct net_device *dev, struct iw_point *p)
2178{
2179 struct ieee_param *param;
2180 int ret = 0;
7c1f4203 2181 struct _adapter *padapter = (struct _adapter *) netdev_priv(dev);
2865d42c
LF
2182
2183 if (p->length < sizeof(struct ieee_param) || !p->pointer)
2184 return -EINVAL;
91d435fe
VO
2185 param = memdup_user(p->pointer, p->length);
2186 if (IS_ERR(param))
2187 return PTR_ERR(param);
2865d42c
LF
2188 switch (param->cmd) {
2189 case IEEE_CMD_SET_WPA_PARAM:
2190 ret = wpa_set_param(dev, param->u.wpa_param.name,
2191 param->u.wpa_param.value);
2192 break;
2193 case IEEE_CMD_SET_WPA_IE:
2194 ret = r871x_set_wpa_ie(padapter, (char *)param->u.wpa_ie.data,
2195 (u16)param->u.wpa_ie.len);
2196 break;
2197 case IEEE_CMD_SET_ENCRYPTION:
2198 ret = wpa_set_encryption(dev, param, p->length);
2199 break;
2200 case IEEE_CMD_MLME:
2201 ret = wpa_mlme(dev, param->u.mlme.command,
2202 param->u.mlme.reason_code);
2203 break;
2204 default:
2205 ret = -EOPNOTSUPP;
2206 break;
2207 }
2208 if (ret == 0 && copy_to_user(p->pointer, param, p->length))
2209 ret = -EFAULT;
646da830 2210 kfree(param);
2865d42c
LF
2211 return ret;
2212}
2213
2214/* based on "driver_ipw" and for hostapd */
2215int r871x_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
2216{
2217 struct iwreq *wrq = (struct iwreq *)rq;
2218
2219 switch (cmd) {
2220 case RTL_IOCTL_WPA_SUPPLICANT:
2221 return wpa_supplicant_ioctl(dev, &wrq->u.data);
2222 default:
2223 return -EOPNOTSUPP;
2224 }
2225 return 0;
2226}
2227
2228static iw_handler r8711_handlers[] = {
2229 NULL, /* SIOCSIWCOMMIT */
2230 r8711_wx_get_name, /* SIOCGIWNAME */
2231 dummy, /* SIOCSIWNWID */
2232 dummy, /* SIOCGIWNWID */
2233 r8711_wx_set_freq, /* SIOCSIWFREQ */
2234 r8711_wx_get_freq, /* SIOCGIWFREQ */
2235 r8711_wx_set_mode, /* SIOCSIWMODE */
2236 r8711_wx_get_mode, /* SIOCGIWMODE */
2237 dummy, /* SIOCSIWSENS */
2238 r8711_wx_get_sens, /* SIOCGIWSENS */
2239 NULL, /* SIOCSIWRANGE */
2240 r8711_wx_get_range, /* SIOCGIWRANGE */
2241 r871x_wx_set_priv, /* SIOCSIWPRIV */
2242 NULL, /* SIOCGIWPRIV */
2243 NULL, /* SIOCSIWSTATS */
2244 NULL, /* SIOCGIWSTATS */
2245 dummy, /* SIOCSIWSPY */
2246 dummy, /* SIOCGIWSPY */
2247 NULL, /* SIOCGIWTHRSPY */
2248 NULL, /* SIOCWIWTHRSPY */
2249 r8711_wx_set_wap, /* SIOCSIWAP */
2250 r8711_wx_get_wap, /* SIOCGIWAP */
2251 r871x_wx_set_mlme, /* request MLME operation;
2252 * uses struct iw_mlme */
2253 dummy, /* SIOCGIWAPLIST -- deprecated */
2254 r8711_wx_set_scan, /* SIOCSIWSCAN */
2255 r8711_wx_get_scan, /* SIOCGIWSCAN */
2256 r8711_wx_set_essid, /* SIOCSIWESSID */
2257 r8711_wx_get_essid, /* SIOCGIWESSID */
2258 dummy, /* SIOCSIWNICKN */
2259 r871x_wx_get_nick, /* SIOCGIWNICKN */
2260 NULL, /* -- hole -- */
2261 NULL, /* -- hole -- */
2262 r8711_wx_set_rate, /* SIOCSIWRATE */
2263 r8711_wx_get_rate, /* SIOCGIWRATE */
2264 dummy, /* SIOCSIWRTS */
2265 r8711_wx_get_rts, /* SIOCGIWRTS */
2266 r8711_wx_set_frag, /* SIOCSIWFRAG */
2267 r8711_wx_get_frag, /* SIOCGIWFRAG */
2268 dummy, /* SIOCSIWTXPOW */
2269 dummy, /* SIOCGIWTXPOW */
2270 dummy, /* SIOCSIWRETRY */
2271 r8711_wx_get_retry, /* SIOCGIWRETRY */
2272 r8711_wx_set_enc, /* SIOCSIWENCODE */
2273 r8711_wx_get_enc, /* SIOCGIWENCODE */
2274 dummy, /* SIOCSIWPOWER */
2275 r8711_wx_get_power, /* SIOCGIWPOWER */
2276 NULL, /*---hole---*/
2277 NULL, /*---hole---*/
2278 r871x_wx_set_gen_ie, /* SIOCSIWGENIE */
2279 NULL, /* SIOCGIWGENIE */
2280 r871x_wx_set_auth, /* SIOCSIWAUTH */
2281 NULL, /* SIOCGIWAUTH */
2282 r871x_wx_set_enc_ext, /* SIOCSIWENCODEEXT */
2283 NULL, /* SIOCGIWENCODEEXT */
2284 r871x_wx_set_pmkid, /* SIOCSIWPMKSA */
2285 NULL, /*---hole---*/
2286};
2287
2288static const struct iw_priv_args r8711_private_args[] = {
2289 {
2290 SIOCIWFIRSTPRIV + 0x0,
2291 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "read32"
2292 },
2293 {
2294 SIOCIWFIRSTPRIV + 0x1,
2295 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "write32"
2296 },
2297 {
2298 SIOCIWFIRSTPRIV + 0x2, 0, 0, "driver_ext"
2299 },
2300 {
2301 SIOCIWFIRSTPRIV + 0x3, 0, 0, "mp_ioctl"
2302 },
2303 {
2304 SIOCIWFIRSTPRIV + 0x4,
2305 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "apinfo"
2306 },
2307 {
2308 SIOCIWFIRSTPRIV + 0x5,
2309 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "setpid"
2310 },
2311 {
2312 SIOCIWFIRSTPRIV + 0x6,
2313 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "wps_start"
c6dc001f
AB
2314 },
2315 {
2316 SIOCIWFIRSTPRIV + 0x7,
2317 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "chplan"
2865d42c
LF
2318 }
2319};
2320
2321static iw_handler r8711_private_handler[] = {
2322 r8711_wx_read32,
2323 r8711_wx_write32,
2324 r8711_drvext_hdl,
2325 r871x_mp_ioctl_hdl,
2326 r871x_get_ap_info, /*for MM DTV platform*/
2327 r871x_set_pid,
c6dc001f
AB
2328 r871x_wps_start,
2329 r871x_set_chplan
2865d42c
LF
2330};
2331
2332static struct iw_statistics *r871x_get_wireless_stats(struct net_device *dev)
2333{
7c1f4203 2334 struct _adapter *padapter = (struct _adapter *) netdev_priv(dev);
2865d42c
LF
2335 struct iw_statistics *piwstats = &padapter->iwstats;
2336 int tmp_level = 0;
2337 int tmp_qual = 0;
2338 int tmp_noise = 0;
2339
2340 if (check_fwstate(&padapter->mlmepriv, _FW_LINKED) != true) {
2341 piwstats->qual.qual = 0;
2342 piwstats->qual.level = 0;
2343 piwstats->qual.noise = 0;
2344 } else {
2345 /* show percentage, we need transfer dbm to orignal value. */
2346 tmp_level = padapter->recvpriv.fw_rssi;
2347 tmp_qual = padapter->recvpriv.signal;
2348 tmp_noise = padapter->recvpriv.noise;
2349 piwstats->qual.level = tmp_level;
da3e6ec2 2350 piwstats->qual.qual = tmp_qual;
2865d42c
LF
2351 piwstats->qual.noise = tmp_noise;
2352 }
2353 piwstats->qual.updated = IW_QUAL_ALL_UPDATED;
2354 return &padapter->iwstats;
2355}
2356
2357struct iw_handler_def r871x_handlers_def = {
2358 .standard = r8711_handlers,
b330f606 2359 .num_standard = ARRAY_SIZE(r8711_handlers),
2865d42c
LF
2360 .private = r8711_private_handler,
2361 .private_args = (struct iw_priv_args *)r8711_private_args,
b330f606 2362 .num_private = ARRAY_SIZE(r8711_private_handler),
2865d42c
LF
2363 .num_private_args = sizeof(r8711_private_args) /
2364 sizeof(struct iw_priv_args),
c6dc001f 2365 .get_wireless_stats = r871x_get_wireless_stats
2865d42c 2366};