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