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