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