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