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