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