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