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