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