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