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