blob: e70513d06a351c1931df501f5fcb1c27d55533b7 [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>
Aya Mahfouz22905b82015-03-04 09:00:02 +020049#include <linux/etherdevice.h>
50
Larry Finger2865d422010-08-20 10:15:30 -050051
Ali Baharc6dc0012011-09-04 03:14:20 +080052#define RTL_IOCTL_WPA_SUPPLICANT (SIOCIWFIRSTPRIV + 0x1E)
Larry Finger2865d422010-08-20 10:15:30 -050053
54#define SCAN_ITEM_SIZE 768
55#define MAX_CUSTOM_LEN 64
56#define RATE_COUNT 4
57
58
59static const u32 rtl8180_rates[] = {1000000, 2000000, 5500000, 11000000,
60 6000000, 9000000, 12000000, 18000000,
61 24000000, 36000000, 48000000, 54000000};
62
63static const long ieee80211_wlan_frequencies[] = {
64 2412, 2417, 2422, 2427,
65 2432, 2437, 2442, 2447,
66 2452, 2457, 2462, 2467,
67 2472, 2484
68};
69
70static const char * const iw_operation_mode[] = {
71 "Auto", "Ad-Hoc", "Managed", "Master", "Repeater", "Secondary",
72 "Monitor"
73};
74
Larry Finger2865d422010-08-20 10:15:30 -050075void r8712_indicate_wx_assoc_event(struct _adapter *padapter)
76{
77 union iwreq_data wrqu;
78 struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
79
80 wrqu.ap_addr.sa_family = ARPHRD_ETHER;
81 memcpy(wrqu.ap_addr.sa_data, pmlmepriv->cur_network.network.MacAddress,
82 ETH_ALEN);
83 wireless_send_event(padapter->pnetdev, SIOCGIWAP, &wrqu, NULL);
84}
85
86void r8712_indicate_wx_disassoc_event(struct _adapter *padapter)
87{
88 union iwreq_data wrqu;
89
90 wrqu.ap_addr.sa_family = ARPHRD_ETHER;
Aya Mahfouz22905b82015-03-04 09:00:02 +020091 eth_zero_addr(wrqu.ap_addr.sa_data);
Larry Finger2865d422010-08-20 10:15:30 -050092 wireless_send_event(padapter->pnetdev, SIOCGIWAP, &wrqu, NULL);
93}
94
95static inline void handle_pairwise_key(struct sta_info *psta,
96 struct ieee_param *param,
97 struct _adapter *padapter)
98{
99 /* pairwise key */
100 memcpy(psta->x_UncstKey.skey, param->u.crypt.key,
101 (param->u.crypt. key_len > 16 ? 16 : param->u.crypt.key_len));
102 if (strcmp(param->u.crypt.alg, "TKIP") == 0) { /* set mic key */
103 memcpy(psta->tkiptxmickey. skey, &(param->u.crypt.
104 key[16]), 8);
105 memcpy(psta->tkiprxmickey. skey, &(param->u.crypt.
106 key[24]), 8);
107 padapter->securitypriv. busetkipkey = false;
Vaishali Thakkar875b7de2015-02-25 09:35:32 +0530108 mod_timer(&padapter->securitypriv.tkip_timer,
109 jiffies + msecs_to_jiffies(50));
Larry Finger2865d422010-08-20 10:15:30 -0500110 }
111 r8712_setstakey_cmd(padapter, (unsigned char *)psta, true);
112}
113
114static inline void handle_group_key(struct ieee_param *param,
115 struct _adapter *padapter)
116{
Alison Schofield29b1b612015-10-06 14:40:58 -0700117 if (param->u.crypt.idx > 0 &&
Larry Finger2865d422010-08-20 10:15:30 -0500118 param->u.crypt.idx < 3) {
119 /* group key idx is 1 or 2 */
120 memcpy(padapter->securitypriv.XGrpKey[param->u.crypt.
121 idx-1].skey, param->u.crypt.key, (param->u.crypt.key_len
122 > 16 ? 16 : param->u.crypt.key_len));
123 memcpy(padapter->securitypriv.XGrptxmickey[param->
124 u.crypt.idx-1].skey, &(param->u.crypt.key[16]), 8);
125 memcpy(padapter->securitypriv. XGrprxmickey[param->
126 u.crypt.idx-1].skey, &(param->u.crypt.key[24]), 8);
127 padapter->securitypriv.binstallGrpkey = true;
128 r8712_set_key(padapter, &padapter->securitypriv,
129 param->u.crypt.idx);
130 if (padapter->registrypriv.power_mgnt > PS_MODE_ACTIVE) {
131 if (padapter->registrypriv.power_mgnt != padapter->
132 pwrctrlpriv.pwr_mode)
Vaishali Thakkar875b7de2015-02-25 09:35:32 +0530133 mod_timer(&padapter->mlmepriv.dhcp_timer,
134 jiffies + msecs_to_jiffies(60000));
Larry Finger2865d422010-08-20 10:15:30 -0500135 }
136 }
137}
138
139static inline char *translate_scan(struct _adapter *padapter,
140 struct iw_request_info *info,
141 struct wlan_network *pnetwork,
142 char *start, char *stop)
143{
144 struct iw_event iwe;
145 struct ieee80211_ht_cap *pht_capie;
146 char *current_val;
Larry Finger2865d422010-08-20 10:15:30 -0500147 s8 *p;
148 u32 i = 0, ht_ielen = 0;
149 u16 cap, ht_cap = false, mcs_rate;
Sudip Mukherjeee29d3eb2014-10-27 17:42:25 +0530150 u8 rssi;
Larry Finger2865d422010-08-20 10:15:30 -0500151
152 if ((pnetwork->network.Configuration.DSConfig < 1) ||
153 (pnetwork->network.Configuration.DSConfig > 14)) {
154 if (pnetwork->network.Configuration.DSConfig < 1)
155 pnetwork->network.Configuration.DSConfig = 1;
156 else
157 pnetwork->network.Configuration.DSConfig = 14;
158 }
159 /* AP MAC address */
160 iwe.cmd = SIOCGIWAP;
161 iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
Haneen Mohammede0e982b2015-03-16 18:41:31 +0300162 ether_addr_copy(iwe.u.ap_addr.sa_data, pnetwork->network.MacAddress);
Larry Finger2865d422010-08-20 10:15:30 -0500163 start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_ADDR_LEN);
164 /* Add the ESSID */
165 iwe.cmd = SIOCGIWESSID;
166 iwe.u.data.flags = 1;
Przemo Firszt0024a1e2012-12-10 23:21:22 +0000167 iwe.u.data.length = min_t(u32, pnetwork->network.Ssid.SsidLength, 32);
Larry Finger2865d422010-08-20 10:15:30 -0500168 start = iwe_stream_add_point(info, start, stop, &iwe,
169 pnetwork->network.Ssid.Ssid);
170 /* parsing HT_CAP_IE */
171 p = r8712_get_ie(&pnetwork->network.IEs[12], _HT_CAPABILITY_IE_,
172 &ht_ielen, pnetwork->network.IELength - 12);
173 if (p && ht_ielen > 0) {
174 ht_cap = true;
175 pht_capie = (struct ieee80211_ht_cap *)(p + 2);
Max Perepelitsyn0636b462015-01-02 14:08:08 +0600176 memcpy(&mcs_rate, pht_capie->supp_mcs_set, 2);
Larry Finger2865d422010-08-20 10:15:30 -0500177 }
178 /* Add the protocol name */
179 iwe.cmd = SIOCGIWNAME;
Joshua Clayton7fb539e2015-08-05 17:17:21 -0700180 if (r8712_is_cckratesonly_included(pnetwork->network.rates)) {
Luis de Bethencourt1ca96882015-10-19 18:14:29 +0100181 if (ht_cap)
Larry Finger2865d422010-08-20 10:15:30 -0500182 snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11bn");
183 else
184 snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11b");
Joshua Clayton7fb539e2015-08-05 17:17:21 -0700185 } else if (r8712_is_cckrates_included(pnetwork->network.rates)) {
Luis de Bethencourt1ca96882015-10-19 18:14:29 +0100186 if (ht_cap)
Larry Finger2865d422010-08-20 10:15:30 -0500187 snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11bgn");
188 else
189 snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11bg");
190 } else {
Luis de Bethencourt1ca96882015-10-19 18:14:29 +0100191 if (ht_cap)
Larry Finger2865d422010-08-20 10:15:30 -0500192 snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11gn");
193 else
194 snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11g");
195 }
196 start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_CHAR_LEN);
197 /* Add mode */
198 iwe.cmd = SIOCGIWMODE;
199 memcpy((u8 *)&cap, r8712_get_capability_from_ie(pnetwork->network.IEs),
200 2);
201 cap = le16_to_cpu(cap);
202 if (cap & (WLAN_CAPABILITY_IBSS|WLAN_CAPABILITY_BSS)) {
203 if (cap & WLAN_CAPABILITY_BSS)
204 iwe.u.mode = (u32)IW_MODE_MASTER;
205 else
206 iwe.u.mode = (u32)IW_MODE_ADHOC;
207 start = iwe_stream_add_event(info, start, stop, &iwe,
208 IW_EV_UINT_LEN);
209 }
210 /* Add frequency/channel */
211 iwe.cmd = SIOCGIWFREQ;
212 {
Justin P. Mattockbe10ac22012-05-07 07:38:22 -0700213 /* check legal index */
Larry Finger2865d422010-08-20 10:15:30 -0500214 u8 dsconfig = pnetwork->network.Configuration.DSConfig;
Tapasweni Pathak02a29d22014-09-24 16:34:56 +0530215
Larry Finger2865d422010-08-20 10:15:30 -0500216 if (dsconfig >= 1 && dsconfig <= sizeof(
217 ieee80211_wlan_frequencies) / sizeof(long))
218 iwe.u.freq.m = (s32)(ieee80211_wlan_frequencies[
219 pnetwork->network.Configuration.
220 DSConfig - 1] * 100000);
221 else
222 iwe.u.freq.m = 0;
223 }
224 iwe.u.freq.e = (s16)1;
225 iwe.u.freq.i = (u8)pnetwork->network.Configuration.DSConfig;
226 start = iwe_stream_add_event(info, start, stop, &iwe,
227 IW_EV_FREQ_LEN);
228 /* Add encryption capability */
229 iwe.cmd = SIOCGIWENCODE;
230 if (cap & WLAN_CAPABILITY_PRIVACY)
231 iwe.u.data.flags = (u16)(IW_ENCODE_ENABLED |
232 IW_ENCODE_NOKEY);
233 else
234 iwe.u.data.flags = (u16)(IW_ENCODE_DISABLED);
235 iwe.u.data.length = (u16)0;
236 start = iwe_stream_add_point(info, start, stop, &iwe,
237 pnetwork->network.Ssid.Ssid);
238 /*Add basic and extended rates */
239 current_val = start + iwe_stream_lcp_len(info);
240 iwe.cmd = SIOCGIWRATE;
241 iwe.u.bitrate.fixed = 0;
242 iwe.u.bitrate.disabled = 0;
243 iwe.u.bitrate.value = 0;
244 i = 0;
Joshua Clayton7fb539e2015-08-05 17:17:21 -0700245 while (pnetwork->network.rates[i] != 0) {
Larry Finger2865d422010-08-20 10:15:30 -0500246 /* Bit rate given in 500 kb/s units */
Joshua Clayton7fb539e2015-08-05 17:17:21 -0700247 iwe.u.bitrate.value = (pnetwork->network.rates[i++] &
Larry Finger2865d422010-08-20 10:15:30 -0500248 0x7F) * 500000;
249 current_val = iwe_stream_add_value(info, start, current_val,
250 stop, &iwe, IW_EV_PARAM_LEN);
251 }
252 /* Check if we added any event */
253 if ((current_val - start) > iwe_stream_lcp_len(info))
254 start = current_val;
255 /* parsing WPA/WPA2 IE */
256 {
Ali Baharc13b6f22011-09-04 03:14:15 +0800257 u8 buf[MAX_WPA_IE_LEN];
258 u8 wpa_ie[255], rsn_ie[255];
Larry Finger2865d422010-08-20 10:15:30 -0500259 u16 wpa_len = 0, rsn_len = 0;
Dan Carpenterd9364352011-02-09 01:45:13 +0300260 int n;
Tapasweni Pathak02a29d22014-09-24 16:34:56 +0530261
Sudip Mukherjeee29d3eb2014-10-27 17:42:25 +0530262 r8712_get_sec_ie(pnetwork->network.IEs,
263 pnetwork->network.IELength, rsn_ie, &rsn_len,
264 wpa_ie, &wpa_len);
Larry Finger2865d422010-08-20 10:15:30 -0500265 if (wpa_len > 0) {
Larry Finger2865d422010-08-20 10:15:30 -0500266 memset(buf, 0, MAX_WPA_IE_LEN);
Dan Carpenterd9364352011-02-09 01:45:13 +0300267 n = sprintf(buf, "wpa_ie=");
268 for (i = 0; i < wpa_len; i++) {
Javier M. Mellid2657c302011-04-02 03:02:12 +0200269 n += snprintf(buf + n, MAX_WPA_IE_LEN - n,
270 "%02x", wpa_ie[i]);
Dan Carpenterd9364352011-02-09 01:45:13 +0300271 if (n >= MAX_WPA_IE_LEN)
272 break;
273 }
Larry Finger2865d422010-08-20 10:15:30 -0500274 memset(&iwe, 0, sizeof(iwe));
275 iwe.cmd = IWEVCUSTOM;
276 iwe.u.data.length = (u16)strlen(buf);
277 start = iwe_stream_add_point(info, start, stop,
278 &iwe, buf);
279 memset(&iwe, 0, sizeof(iwe));
280 iwe.cmd = IWEVGENIE;
281 iwe.u.data.length = (u16)wpa_len;
282 start = iwe_stream_add_point(info, start, stop,
283 &iwe, wpa_ie);
284 }
285 if (rsn_len > 0) {
Larry Finger2865d422010-08-20 10:15:30 -0500286 memset(buf, 0, MAX_WPA_IE_LEN);
Dan Carpenterd9364352011-02-09 01:45:13 +0300287 n = sprintf(buf, "rsn_ie=");
288 for (i = 0; i < rsn_len; i++) {
Javier M. Mellid2657c302011-04-02 03:02:12 +0200289 n += snprintf(buf + n, MAX_WPA_IE_LEN - n,
290 "%02x", rsn_ie[i]);
Dan Carpenterd9364352011-02-09 01:45:13 +0300291 if (n >= MAX_WPA_IE_LEN)
292 break;
293 }
Larry Finger2865d422010-08-20 10:15:30 -0500294 memset(&iwe, 0, sizeof(iwe));
295 iwe.cmd = IWEVCUSTOM;
296 iwe.u.data.length = strlen(buf);
297 start = iwe_stream_add_point(info, start, stop,
298 &iwe, buf);
299 memset(&iwe, 0, sizeof(iwe));
300 iwe.cmd = IWEVGENIE;
301 iwe.u.data.length = rsn_len;
302 start = iwe_stream_add_point(info, start, stop, &iwe,
303 rsn_ie);
304 }
305 }
306
307 { /* parsing WPS IE */
Ali Baharc13b6f22011-09-04 03:14:15 +0800308 u8 wps_ie[512];
Larry Finger2865d422010-08-20 10:15:30 -0500309 uint wps_ielen;
310
311 if (r8712_get_wps_ie(pnetwork->network.IEs,
312 pnetwork->network.IELength,
Luis de Bethencourt1ca96882015-10-19 18:14:29 +0100313 wps_ie, &wps_ielen)) {
Larry Finger2865d422010-08-20 10:15:30 -0500314 if (wps_ielen > 2) {
315 iwe.cmd = IWEVGENIE;
316 iwe.u.data.length = (u16)wps_ielen;
317 start = iwe_stream_add_point(info, start, stop,
318 &iwe, wps_ie);
319 }
320 }
321 }
322 /* Add quality statistics */
323 iwe.cmd = IWEVQUAL;
324 rssi = r8712_signal_scale_mapping(pnetwork->network.Rssi);
325 /* we only update signal_level (signal strength) that is rssi. */
326 iwe.u.qual.updated = (u8)(IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_UPDATED |
327 IW_QUAL_NOISE_INVALID);
328 iwe.u.qual.level = rssi; /* signal strength */
329 iwe.u.qual.qual = 0; /* signal quality */
330 iwe.u.qual.noise = 0; /* noise level */
331 start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_QUAL_LEN);
332 /* how to translate rssi to ?% */
Larry Finger2865d422010-08-20 10:15:30 -0500333 return start;
334}
335
336static int wpa_set_auth_algs(struct net_device *dev, u32 value)
337{
Julia Lawall8f47c282015-03-29 14:54:12 +0200338 struct _adapter *padapter = netdev_priv(dev);
Larry Finger2865d422010-08-20 10:15:30 -0500339 int ret = 0;
340
341 if ((value & AUTH_ALG_SHARED_KEY) && (value & AUTH_ALG_OPEN_SYSTEM)) {
342 padapter->securitypriv.ndisencryptstatus =
343 Ndis802_11Encryption1Enabled;
344 padapter->securitypriv.ndisauthtype =
345 Ndis802_11AuthModeAutoSwitch;
346 padapter->securitypriv.AuthAlgrthm = 3;
347 } else if (value & AUTH_ALG_SHARED_KEY) {
348 padapter->securitypriv.ndisencryptstatus =
349 Ndis802_11Encryption1Enabled;
350 padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeShared;
351 padapter->securitypriv.AuthAlgrthm = 1;
352 } else if (value & AUTH_ALG_OPEN_SYSTEM) {
353 if (padapter->securitypriv.ndisauthtype <
354 Ndis802_11AuthModeWPAPSK) {
355 padapter->securitypriv.ndisauthtype =
356 Ndis802_11AuthModeOpen;
357 padapter->securitypriv.AuthAlgrthm = 0;
358 }
Luis de Bethencourt168a2c12015-10-19 18:15:29 +0100359 } else {
Larry Finger2865d422010-08-20 10:15:30 -0500360 ret = -EINVAL;
Luis de Bethencourt168a2c12015-10-19 18:15:29 +0100361 }
Larry Finger2865d422010-08-20 10:15:30 -0500362 return ret;
363}
364
365static int wpa_set_encryption(struct net_device *dev, struct ieee_param *param,
366 u32 param_len)
367{
368 int ret = 0;
369 u32 wep_key_idx, wep_key_len = 0;
370 struct NDIS_802_11_WEP *pwep = NULL;
Julia Lawall8f47c282015-03-29 14:54:12 +0200371 struct _adapter *padapter = netdev_priv(dev);
Larry Finger2865d422010-08-20 10:15:30 -0500372 struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
373 struct security_priv *psecuritypriv = &padapter->securitypriv;
374
375 param->u.crypt.err = 0;
376 param->u.crypt.alg[IEEE_CRYPT_ALG_NAME_LEN - 1] = '\0';
377 if (param_len != (u32)((u8 *) param->u.crypt.key - (u8 *)param) +
378 param->u.crypt.key_len)
379 return -EINVAL;
Wei Yongjun779477f2012-08-26 09:22:33 +0800380 if (is_broadcast_ether_addr(param->sta_addr)) {
Larry Finger2865d422010-08-20 10:15:30 -0500381 if (param->u.crypt.idx >= WEP_KEYS) {
382 /* for large key indices, set the default (0) */
383 param->u.crypt.idx = 0;
384 }
Luis de Bethencourt168a2c12015-10-19 18:15:29 +0100385 } else {
Larry Finger2865d422010-08-20 10:15:30 -0500386 return -EINVAL;
Luis de Bethencourt168a2c12015-10-19 18:15:29 +0100387 }
Larry Finger2865d422010-08-20 10:15:30 -0500388 if (strcmp(param->u.crypt.alg, "WEP") == 0) {
Przemo Firszt87a573a2012-12-10 23:21:21 +0000389 netdev_info(dev, "r8712u: %s: crypt.alg = WEP\n", __func__);
Larry Finger2865d422010-08-20 10:15:30 -0500390 padapter->securitypriv.ndisencryptstatus =
391 Ndis802_11Encryption1Enabled;
392 padapter->securitypriv.PrivacyAlgrthm = _WEP40_;
393 padapter->securitypriv.XGrpPrivacy = _WEP40_;
394 wep_key_idx = param->u.crypt.idx;
395 wep_key_len = param->u.crypt.key_len;
396 if (wep_key_idx >= WEP_KEYS)
397 wep_key_idx = 0;
398 if (wep_key_len > 0) {
399 wep_key_len = wep_key_len <= 5 ? 5 : 13;
Vitaly Osipov91d435f2014-05-24 18:19:27 +1000400 pwep = kmalloc((u32)(wep_key_len +
Tapasweni Pathak57b66862014-09-21 06:42:21 +0530401 FIELD_OFFSET(struct NDIS_802_11_WEP,
402 KeyMaterial)), GFP_ATOMIC);
Larry Finger2865d422010-08-20 10:15:30 -0500403 if (pwep == NULL)
404 return -ENOMEM;
405 memset(pwep, 0, sizeof(struct NDIS_802_11_WEP));
406 pwep->KeyLength = wep_key_len;
407 pwep->Length = wep_key_len +
408 FIELD_OFFSET(struct NDIS_802_11_WEP,
409 KeyMaterial);
410 if (wep_key_len == 13) {
411 padapter->securitypriv.PrivacyAlgrthm =
412 _WEP104_;
413 padapter->securitypriv.XGrpPrivacy =
414 _WEP104_;
415 }
Luis de Bethencourt168a2c12015-10-19 18:15:29 +0100416 } else {
Larry Finger2865d422010-08-20 10:15:30 -0500417 return -EINVAL;
Luis de Bethencourt168a2c12015-10-19 18:15:29 +0100418 }
Larry Finger2865d422010-08-20 10:15:30 -0500419 pwep->KeyIndex = wep_key_idx;
420 pwep->KeyIndex |= 0x80000000;
421 memcpy(pwep->KeyMaterial, param->u.crypt.key, pwep->KeyLength);
422 if (param->u.crypt.set_tx) {
423 if (r8712_set_802_11_add_wep(padapter, pwep) ==
424 (u8)_FAIL)
425 ret = -EOPNOTSUPP;
426 } else {
427 /* don't update "psecuritypriv->PrivacyAlgrthm" and
428 * "psecuritypriv->PrivacyKeyIndex=keyid", but can
429 * r8712_set_key to fw/cam
430 */
431 if (wep_key_idx >= WEP_KEYS) {
432 ret = -EOPNOTSUPP;
433 goto exit;
434 }
435 memcpy(&(psecuritypriv->DefKey[wep_key_idx].
436 skey[0]), pwep->KeyMaterial,
437 pwep->KeyLength);
438 psecuritypriv->DefKeylen[wep_key_idx] =
439 pwep->KeyLength;
440 r8712_set_key(padapter, psecuritypriv, wep_key_idx);
441 }
442 goto exit;
443 }
444 if (padapter->securitypriv.AuthAlgrthm == 2) { /* 802_1x */
445 struct sta_info *psta, *pbcmc_sta;
446 struct sta_priv *pstapriv = &padapter->stapriv;
447
448 if (check_fwstate(pmlmepriv, WIFI_STATION_STATE |
Luis de Bethencourt1ca96882015-10-19 18:14:29 +0100449 WIFI_MP_STATE)) { /* sta mode */
Larry Finger2865d422010-08-20 10:15:30 -0500450 psta = r8712_get_stainfo(pstapriv,
451 get_bssid(pmlmepriv));
452 if (psta) {
453 psta->ieee8021x_blocked = false;
454 if ((padapter->securitypriv.ndisencryptstatus ==
455 Ndis802_11Encryption2Enabled) ||
456 (padapter->securitypriv.ndisencryptstatus ==
457 Ndis802_11Encryption3Enabled))
458 psta->XPrivacy = padapter->
459 securitypriv.PrivacyAlgrthm;
460 if (param->u.crypt.set_tx == 1)
461 handle_pairwise_key(psta, param,
462 padapter);
463 else /* group key */
464 handle_group_key(param, padapter);
465 }
466 pbcmc_sta = r8712_get_bcmc_stainfo(padapter);
467 if (pbcmc_sta) {
468 pbcmc_sta->ieee8021x_blocked = false;
469 if ((padapter->securitypriv.ndisencryptstatus ==
470 Ndis802_11Encryption2Enabled) ||
471 (padapter->securitypriv.ndisencryptstatus ==
472 Ndis802_11Encryption3Enabled))
473 pbcmc_sta->XPrivacy =
474 padapter->securitypriv.
475 PrivacyAlgrthm;
476 }
477 }
478 }
479exit:
Tapasweni Pathak646da832014-10-08 20:41:26 +0530480 kfree(pwep);
Larry Finger2865d422010-08-20 10:15:30 -0500481 return ret;
482}
483
484static int r871x_set_wpa_ie(struct _adapter *padapter, char *pie,
485 unsigned short ielen)
486{
Sudip Mukherjeee29d3eb2014-10-27 17:42:25 +0530487 u8 *buf = NULL;
Larry Finger2865d422010-08-20 10:15:30 -0500488 int group_cipher = 0, pairwise_cipher = 0;
489 int ret = 0;
490
491 if ((ielen > MAX_WPA_IE_LEN) || (pie == NULL))
492 return -EINVAL;
493 if (ielen) {
Vitaly Osipov91d435f2014-05-24 18:19:27 +1000494 buf = kmemdup(pie, ielen, GFP_ATOMIC);
Larry Finger2865d422010-08-20 10:15:30 -0500495 if (buf == NULL)
496 return -ENOMEM;
Larry Finger2865d422010-08-20 10:15:30 -0500497 if (ielen < RSN_HEADER_LEN) {
Ali Bahar2192e602011-09-04 03:14:24 +0800498 ret = -EINVAL;
Larry Finger2865d422010-08-20 10:15:30 -0500499 goto exit;
500 }
501 if (r8712_parse_wpa_ie(buf, ielen, &group_cipher,
502 &pairwise_cipher) == _SUCCESS) {
503 padapter->securitypriv.AuthAlgrthm = 2;
504 padapter->securitypriv.ndisauthtype =
505 Ndis802_11AuthModeWPAPSK;
506 }
507 if (r8712_parse_wpa2_ie(buf, ielen, &group_cipher,
508 &pairwise_cipher) == _SUCCESS) {
509 padapter->securitypriv.AuthAlgrthm = 2;
510 padapter->securitypriv.ndisauthtype =
511 Ndis802_11AuthModeWPA2PSK;
512 }
513 switch (group_cipher) {
514 case WPA_CIPHER_NONE:
515 padapter->securitypriv.XGrpPrivacy =
516 _NO_PRIVACY_;
517 padapter->securitypriv.ndisencryptstatus =
518 Ndis802_11EncryptionDisabled;
519 break;
520 case WPA_CIPHER_WEP40:
521 padapter->securitypriv.XGrpPrivacy = _WEP40_;
522 padapter->securitypriv.ndisencryptstatus =
523 Ndis802_11Encryption1Enabled;
524 break;
525 case WPA_CIPHER_TKIP:
526 padapter->securitypriv.XGrpPrivacy = _TKIP_;
527 padapter->securitypriv.ndisencryptstatus =
528 Ndis802_11Encryption2Enabled;
529 break;
530 case WPA_CIPHER_CCMP:
531 padapter->securitypriv.XGrpPrivacy = _AES_;
532 padapter->securitypriv.ndisencryptstatus =
533 Ndis802_11Encryption3Enabled;
534 break;
535 case WPA_CIPHER_WEP104:
536 padapter->securitypriv.XGrpPrivacy = _WEP104_;
537 padapter->securitypriv.ndisencryptstatus =
538 Ndis802_11Encryption1Enabled;
539 break;
540 }
541 switch (pairwise_cipher) {
542 case WPA_CIPHER_NONE:
543 padapter->securitypriv.PrivacyAlgrthm =
544 _NO_PRIVACY_;
545 padapter->securitypriv.ndisencryptstatus =
546 Ndis802_11EncryptionDisabled;
547 break;
548 case WPA_CIPHER_WEP40:
549 padapter->securitypriv.PrivacyAlgrthm = _WEP40_;
550 padapter->securitypriv.ndisencryptstatus =
551 Ndis802_11Encryption1Enabled;
552 break;
553 case WPA_CIPHER_TKIP:
554 padapter->securitypriv.PrivacyAlgrthm = _TKIP_;
555 padapter->securitypriv.ndisencryptstatus =
556 Ndis802_11Encryption2Enabled;
557 break;
558 case WPA_CIPHER_CCMP:
559 padapter->securitypriv.PrivacyAlgrthm = _AES_;
560 padapter->securitypriv.ndisencryptstatus =
561 Ndis802_11Encryption3Enabled;
562 break;
563 case WPA_CIPHER_WEP104:
564 padapter->securitypriv.PrivacyAlgrthm = _WEP104_;
565 padapter->securitypriv.ndisencryptstatus =
566 Ndis802_11Encryption1Enabled;
567 break;
568 }
569 padapter->securitypriv.wps_phase = false;
570 {/* set wps_ie */
571 u16 cnt = 0;
572 u8 eid, wps_oui[4] = {0x0, 0x50, 0xf2, 0x04};
573
574 while (cnt < ielen) {
575 eid = buf[cnt];
576
577 if ((eid == _VENDOR_SPECIFIC_IE_) &&
578 (!memcmp(&buf[cnt+2], wps_oui, 4))) {
Przemo Firszt87a573a2012-12-10 23:21:21 +0000579 netdev_info(padapter->pnetdev, "r8712u: SET WPS_IE\n");
Larry Finger2865d422010-08-20 10:15:30 -0500580 padapter->securitypriv.wps_ie_len =
581 ((buf[cnt+1] + 2) <
582 (MAX_WPA_IE_LEN << 2)) ?
583 (buf[cnt + 1] + 2) :
584 (MAX_WPA_IE_LEN << 2);
585 memcpy(padapter->securitypriv.wps_ie,
586 &buf[cnt],
587 padapter->securitypriv.wps_ie_len);
588 padapter->securitypriv.wps_phase =
589 true;
Przemo Firszt87a573a2012-12-10 23:21:21 +0000590 netdev_info(padapter->pnetdev, "r8712u: SET WPS_IE, wps_phase==true\n");
Larry Finger2865d422010-08-20 10:15:30 -0500591 cnt += buf[cnt+1]+2;
592 break;
Luis de Bethencourt168a2c12015-10-19 18:15:29 +0100593 } else {
Larry Finger2865d422010-08-20 10:15:30 -0500594 cnt += buf[cnt + 1] + 2;
Luis de Bethencourt168a2c12015-10-19 18:15:29 +0100595 }
Larry Finger2865d422010-08-20 10:15:30 -0500596 }
597 }
598 }
599exit:
600 kfree(buf);
601 return ret;
602}
603
604static int r8711_wx_get_name(struct net_device *dev,
605 struct iw_request_info *info,
606 union iwreq_data *wrqu, char *extra)
607{
Julia Lawall8f47c282015-03-29 14:54:12 +0200608 struct _adapter *padapter = netdev_priv(dev);
Larry Finger2865d422010-08-20 10:15:30 -0500609 u32 ht_ielen = 0;
610 char *p;
611 u8 ht_cap = false;
612 struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
Joshua Clayton44367872015-08-05 17:17:18 -0700613 struct wlan_bssid_ex *pcur_bss = &pmlmepriv->cur_network.network;
Joshua Claytondb55b162015-08-05 17:17:20 -0700614 u8 *prates;
Larry Finger2865d422010-08-20 10:15:30 -0500615
616 if (check_fwstate(pmlmepriv, _FW_LINKED|WIFI_ADHOC_MASTER_STATE) ==
617 true) {
618 /* parsing HT_CAP_IE */
619 p = r8712_get_ie(&pcur_bss->IEs[12], _HT_CAPABILITY_IE_,
620 &ht_ielen, pcur_bss->IELength - 12);
621 if (p && ht_ielen > 0)
622 ht_cap = true;
Joshua Clayton7fb539e2015-08-05 17:17:21 -0700623 prates = pcur_bss->rates;
Luis de Bethencourt1ca96882015-10-19 18:14:29 +0100624 if (r8712_is_cckratesonly_included(prates)) {
625 if (ht_cap)
Larry Finger2865d422010-08-20 10:15:30 -0500626 snprintf(wrqu->name, IFNAMSIZ,
627 "IEEE 802.11bn");
628 else
629 snprintf(wrqu->name, IFNAMSIZ,
630 "IEEE 802.11b");
Luis de Bethencourt1ca96882015-10-19 18:14:29 +0100631 } else if (r8712_is_cckrates_included(prates)) {
632 if (ht_cap)
Larry Finger2865d422010-08-20 10:15:30 -0500633 snprintf(wrqu->name, IFNAMSIZ,
634 "IEEE 802.11bgn");
635 else
636 snprintf(wrqu->name, IFNAMSIZ,
637 "IEEE 802.11bg");
638 } else {
Luis de Bethencourt1ca96882015-10-19 18:14:29 +0100639 if (ht_cap)
Larry Finger2865d422010-08-20 10:15:30 -0500640 snprintf(wrqu->name, IFNAMSIZ,
641 "IEEE 802.11gn");
642 else
643 snprintf(wrqu->name, IFNAMSIZ,
644 "IEEE 802.11g");
645 }
Luis de Bethencourt168a2c12015-10-19 18:15:29 +0100646 } else {
Larry Finger2865d422010-08-20 10:15:30 -0500647 snprintf(wrqu->name, IFNAMSIZ, "unassociated");
Luis de Bethencourt168a2c12015-10-19 18:15:29 +0100648 }
Larry Finger2865d422010-08-20 10:15:30 -0500649 return 0;
650}
651
652static const long frequency_list[] = {
653 2412, 2417, 2422, 2427, 2432, 2437, 2442, 2447, 2452, 2457, 2462,
654 2467, 2472, 2484, 4915, 4920, 4925, 4935, 4940, 4945, 4960, 4980,
655 5035, 5040, 5045, 5055, 5060, 5080, 5170, 5180, 5190, 5200, 5210,
656 5220, 5230, 5240, 5260, 5280, 5300, 5320, 5500, 5520, 5540, 5560,
657 5580, 5600, 5620, 5640, 5660, 5680, 5700, 5745, 5765, 5785, 5805,
658 5825
659};
660
661static int r8711_wx_set_freq(struct net_device *dev,
662 struct iw_request_info *info,
663 union iwreq_data *wrqu, char *extra)
664{
Julia Lawall8f47c282015-03-29 14:54:12 +0200665 struct _adapter *padapter = netdev_priv(dev);
Larry Finger2865d422010-08-20 10:15:30 -0500666 struct iw_freq *fwrq = &wrqu->freq;
667 int rc = 0;
668
669/* If setting by frequency, convert to a channel */
670 if ((fwrq->e == 1) &&
671 (fwrq->m >= (int) 2.412e8) &&
672 (fwrq->m <= (int) 2.487e8)) {
673 int f = fwrq->m / 100000;
674 int c = 0;
Tapasweni Pathak02a29d22014-09-24 16:34:56 +0530675
Larry Finger2865d422010-08-20 10:15:30 -0500676 while ((c < 14) && (f != frequency_list[c]))
677 c++;
678 fwrq->e = 0;
679 fwrq->m = c + 1;
680 }
681 /* Setting by channel number */
Luis de Bethencourt168a2c12015-10-19 18:15:29 +0100682 if ((fwrq->m > 14) || (fwrq->e > 0)) {
Larry Finger2865d422010-08-20 10:15:30 -0500683 rc = -EOPNOTSUPP;
Luis de Bethencourt168a2c12015-10-19 18:15:29 +0100684 } else {
Larry Finger2865d422010-08-20 10:15:30 -0500685 int channel = fwrq->m;
Tapasweni Pathak02a29d22014-09-24 16:34:56 +0530686
Luis de Bethencourt168a2c12015-10-19 18:15:29 +0100687 if ((channel < 1) || (channel > 14)) {
Larry Finger2865d422010-08-20 10:15:30 -0500688 rc = -EINVAL;
Luis de Bethencourt168a2c12015-10-19 18:15:29 +0100689 } else {
Larry Finger2865d422010-08-20 10:15:30 -0500690 /* Yes ! We can set it !!! */
691 padapter->registrypriv.channel = channel;
692 }
693 }
694 return rc;
695}
696
697static int r8711_wx_get_freq(struct net_device *dev,
698 struct iw_request_info *info,
699 union iwreq_data *wrqu, char *extra)
700{
Julia Lawall8f47c282015-03-29 14:54:12 +0200701 struct _adapter *padapter = netdev_priv(dev);
Larry Finger2865d422010-08-20 10:15:30 -0500702 struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
Joshua Clayton44367872015-08-05 17:17:18 -0700703 struct wlan_bssid_ex *pcur_bss = &pmlmepriv->cur_network.network;
Larry Finger2865d422010-08-20 10:15:30 -0500704
Luis de Bethencourt1ca96882015-10-19 18:14:29 +0100705 if (check_fwstate(pmlmepriv, _FW_LINKED)) {
Larry Finger2865d422010-08-20 10:15:30 -0500706 wrqu->freq.m = ieee80211_wlan_frequencies[
707 pcur_bss->Configuration.DSConfig-1] * 100000;
708 wrqu->freq.e = 1;
709 wrqu->freq.i = pcur_bss->Configuration.DSConfig;
Ali Bahar2192e602011-09-04 03:14:24 +0800710 } else {
711 return -ENOLINK;
712 }
Larry Finger2865d422010-08-20 10:15:30 -0500713 return 0;
714}
715
716static int r8711_wx_set_mode(struct net_device *dev,
717 struct iw_request_info *a,
718 union iwreq_data *wrqu, char *b)
719{
Julia Lawall8f47c282015-03-29 14:54:12 +0200720 struct _adapter *padapter = netdev_priv(dev);
Larry Finger2865d422010-08-20 10:15:30 -0500721 enum NDIS_802_11_NETWORK_INFRASTRUCTURE networkType;
722
723 switch (wrqu->mode) {
724 case IW_MODE_AUTO:
725 networkType = Ndis802_11AutoUnknown;
726 break;
727 case IW_MODE_ADHOC:
728 networkType = Ndis802_11IBSS;
729 break;
730 case IW_MODE_MASTER:
731 networkType = Ndis802_11APMode;
732 break;
733 case IW_MODE_INFRA:
734 networkType = Ndis802_11Infrastructure;
735 break;
736 default:
737 return -EINVAL;
738 }
739 if (Ndis802_11APMode == networkType)
740 r8712_setopmode_cmd(padapter, networkType);
741 else
742 r8712_setopmode_cmd(padapter, Ndis802_11AutoUnknown);
Ali Bahar2192e602011-09-04 03:14:24 +0800743
744 r8712_set_802_11_infrastructure_mode(padapter, networkType);
Larry Finger2865d422010-08-20 10:15:30 -0500745 return 0;
746}
747
748static int r8711_wx_get_mode(struct net_device *dev, struct iw_request_info *a,
749 union iwreq_data *wrqu, char *b)
750{
Julia Lawall8f47c282015-03-29 14:54:12 +0200751 struct _adapter *padapter = netdev_priv(dev);
Larry Finger2865d422010-08-20 10:15:30 -0500752 struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
753
Luis de Bethencourt1ca96882015-10-19 18:14:29 +0100754 if (check_fwstate(pmlmepriv, WIFI_STATION_STATE))
Larry Finger2865d422010-08-20 10:15:30 -0500755 wrqu->mode = IW_MODE_INFRA;
756 else if (check_fwstate(pmlmepriv,
Luis de Bethencourt1ca96882015-10-19 18:14:29 +0100757 WIFI_ADHOC_MASTER_STATE | WIFI_ADHOC_STATE))
Larry Finger2865d422010-08-20 10:15:30 -0500758 wrqu->mode = IW_MODE_ADHOC;
Luis de Bethencourt1ca96882015-10-19 18:14:29 +0100759 else if (check_fwstate(pmlmepriv, WIFI_AP_STATE))
Larry Finger2865d422010-08-20 10:15:30 -0500760 wrqu->mode = IW_MODE_MASTER;
761 else
762 wrqu->mode = IW_MODE_AUTO;
763 return 0;
764}
765
766static int r871x_wx_set_pmkid(struct net_device *dev,
767 struct iw_request_info *a,
768 union iwreq_data *wrqu, char *extra)
769{
Julia Lawall8f47c282015-03-29 14:54:12 +0200770 struct _adapter *padapter = netdev_priv(dev);
Larry Finger2865d422010-08-20 10:15:30 -0500771 struct security_priv *psecuritypriv = &padapter->securitypriv;
772 struct iw_pmksa *pPMK = (struct iw_pmksa *) extra;
773 u8 strZeroMacAddress[ETH_ALEN] = {0x00};
774 u8 strIssueBssid[ETH_ALEN] = {0x00};
775 u8 j, blInserted = false;
776 int intReturn = false;
777
778/*
Punit Varad32c16d2015-10-14 23:55:54 +0530779 * There are the BSSID information in the bssid.sa_data array.
780 * If cmd is IW_PMKSA_FLUSH, it means the wpa_supplicant wants to clear
781 * all the PMKID information. If cmd is IW_PMKSA_ADD, it means the
782 * wpa_supplicant wants to add a PMKID/BSSID to driver.
783 * If cmd is IW_PMKSA_REMOVE, it means the wpa_supplicant wants to
784 * remove a PMKID/BSSID from driver.
785 */
Larry Finger2865d422010-08-20 10:15:30 -0500786 if (pPMK == NULL)
787 return -EINVAL;
788 memcpy(strIssueBssid, pPMK->bssid.sa_data, ETH_ALEN);
789 switch (pPMK->cmd) {
790 case IW_PMKSA_ADD:
791 if (!memcmp(strIssueBssid, strZeroMacAddress, ETH_ALEN))
792 return intReturn;
Dogukan Ergun07e9e612015-06-13 15:04:26 +0300793 intReturn = true;
Larry Finger2865d422010-08-20 10:15:30 -0500794 blInserted = false;
795 /* overwrite PMKID */
Thomas Cort77e73e82013-10-01 11:26:55 -0400796 for (j = 0; j < NUM_PMKID_CACHE; j++) {
Larry Finger2865d422010-08-20 10:15:30 -0500797 if (!memcmp(psecuritypriv->PMKIDList[j].Bssid,
798 strIssueBssid, ETH_ALEN)) {
799 /* BSSID is matched, the same AP => rewrite
Punit Varad32c16d2015-10-14 23:55:54 +0530800 * with new PMKID.
801 */
Przemo Firszt87a573a2012-12-10 23:21:21 +0000802 netdev_info(dev, "r8712u: %s: BSSID exists in the PMKList.\n",
803 __func__);
Larry Finger2865d422010-08-20 10:15:30 -0500804 memcpy(psecuritypriv->PMKIDList[j].PMKID,
805 pPMK->pmkid, IW_PMKID_LEN);
806 psecuritypriv->PMKIDList[j].bUsed = true;
807 psecuritypriv->PMKIDIndex = j + 1;
808 blInserted = true;
809 break;
810 }
811 }
812 if (!blInserted) {
813 /* Find a new entry */
Przemo Firszt87a573a2012-12-10 23:21:21 +0000814 netdev_info(dev, "r8712u: %s: Use the new entry index = %d for this PMKID.\n",
815 __func__, psecuritypriv->PMKIDIndex);
Larry Finger2865d422010-08-20 10:15:30 -0500816 memcpy(psecuritypriv->PMKIDList[psecuritypriv->
817 PMKIDIndex].Bssid, strIssueBssid, ETH_ALEN);
818 memcpy(psecuritypriv->PMKIDList[psecuritypriv->
819 PMKIDIndex].PMKID, pPMK->pmkid, IW_PMKID_LEN);
820 psecuritypriv->PMKIDList[psecuritypriv->PMKIDIndex].
821 bUsed = true;
Thomas Cort77e73e82013-10-01 11:26:55 -0400822 psecuritypriv->PMKIDIndex++;
Larry Finger2865d422010-08-20 10:15:30 -0500823 if (psecuritypriv->PMKIDIndex == NUM_PMKID_CACHE)
824 psecuritypriv->PMKIDIndex = 0;
825 }
826 break;
827 case IW_PMKSA_REMOVE:
828 intReturn = true;
829 for (j = 0; j < NUM_PMKID_CACHE; j++) {
830 if (!memcmp(psecuritypriv->PMKIDList[j].Bssid,
831 strIssueBssid, ETH_ALEN)) {
832 /* BSSID is matched, the same AP => Remove
Punit Varad32c16d2015-10-14 23:55:54 +0530833 * this PMKID information and reset it.
834 */
Aya Mahfouz22905b82015-03-04 09:00:02 +0200835 eth_zero_addr(psecuritypriv->PMKIDList[j].Bssid);
Larry Finger2865d422010-08-20 10:15:30 -0500836 psecuritypriv->PMKIDList[j].bUsed = false;
837 break;
838 }
839 }
840 break;
841 case IW_PMKSA_FLUSH:
842 memset(psecuritypriv->PMKIDList, 0,
843 sizeof(struct RT_PMKID_LIST) * NUM_PMKID_CACHE);
844 psecuritypriv->PMKIDIndex = 0;
845 intReturn = true;
846 break;
847 default:
Przemo Firszt87a573a2012-12-10 23:21:21 +0000848 netdev_info(dev, "r8712u: %s: unknown Command\n", __func__);
Larry Finger2865d422010-08-20 10:15:30 -0500849 intReturn = false;
850 break;
851 }
852 return intReturn;
853}
854
855static int r8711_wx_get_sens(struct net_device *dev,
856 struct iw_request_info *info,
857 union iwreq_data *wrqu, char *extra)
858{
859 wrqu->sens.value = 0;
860 wrqu->sens.fixed = 0; /* no auto select */
861 wrqu->sens.disabled = 1;
862 return 0;
863}
864
865static int r8711_wx_get_range(struct net_device *dev,
866 struct iw_request_info *info,
867 union iwreq_data *wrqu, char *extra)
868{
869 struct iw_range *range = (struct iw_range *)extra;
870 u16 val;
871 int i;
872
873 wrqu->data.length = sizeof(*range);
874 memset(range, 0, sizeof(*range));
875 /* Let's try to keep this struct in the same order as in
876 * linux/include/wireless.h
877 */
878
879 /* TODO: See what values we can set, and remove the ones we can't
880 * set, or fill them with some default data.
881 */
882 /* ~5 Mb/s real (802.11b) */
883 range->throughput = 5 * 1000 * 1000;
884 /* TODO: 8711 sensitivity ? */
885 /* signal level threshold range */
886 /* percent values between 0 and 100. */
887 range->max_qual.qual = 100;
888 range->max_qual.level = 100;
889 range->max_qual.noise = 100;
890 range->max_qual.updated = 7; /* Updated all three */
891 range->avg_qual.qual = 92; /* > 8% missed beacons is 'bad' */
Justin P. Mattockbe10ac22012-05-07 07:38:22 -0700892 /* TODO: Find real 'good' to 'bad' threshold value for RSSI */
Luis de Bethencourt681cd982015-10-11 14:16:57 +0100893 range->avg_qual.level = 0x100 - 78;
Larry Finger2865d422010-08-20 10:15:30 -0500894 range->avg_qual.noise = 0;
895 range->avg_qual.updated = 7; /* Updated all three */
896 range->num_bitrates = RATE_COUNT;
897 for (i = 0; i < RATE_COUNT && i < IW_MAX_BITRATES; i++)
898 range->bitrate[i] = rtl8180_rates[i];
899 range->min_frag = MIN_FRAG_THRESHOLD;
900 range->max_frag = MAX_FRAG_THRESHOLD;
901 range->pm_capa = 0;
902 range->we_version_compiled = WIRELESS_EXT;
903 range->we_version_source = 16;
904 range->num_channels = 14;
905 for (i = 0, val = 0; i < 14; i++) {
906 /* Include only legal frequencies for some countries */
907 range->freq[val].i = i + 1;
908 range->freq[val].m = ieee80211_wlan_frequencies[i] * 100000;
909 range->freq[val].e = 1;
910 val++;
911 if (val == IW_MAX_FREQUENCIES)
912 break;
913 }
914 range->num_frequency = val;
915 range->enc_capa = IW_ENC_CAPA_WPA |
916 IW_ENC_CAPA_WPA2 |
917 IW_ENC_CAPA_CIPHER_TKIP |
918 IW_ENC_CAPA_CIPHER_CCMP;
919 return 0;
920}
921
Ali Baharc6dc0012011-09-04 03:14:20 +0800922static int r8711_wx_get_rate(struct net_device *dev,
923 struct iw_request_info *info,
924 union iwreq_data *wrqu, char *extra);
925
Larry Finger2865d422010-08-20 10:15:30 -0500926static int r871x_wx_set_priv(struct net_device *dev,
927 struct iw_request_info *info,
928 union iwreq_data *awrq,
929 char *extra)
930{
931 int ret = 0, len = 0;
932 char *ext;
Ali Baharc6dc0012011-09-04 03:14:20 +0800933 struct _adapter *padapter = netdev_priv(dev);
Larry Finger2865d422010-08-20 10:15:30 -0500934 struct iw_point *dwrq = (struct iw_point *)awrq;
935
936 len = dwrq->length;
Vitaly Osipov91d435f2014-05-24 18:19:27 +1000937 ext = memdup_user(dwrq->pointer, len);
938 if (IS_ERR(ext))
939 return PTR_ERR(ext);
Ali Baharc6dc0012011-09-04 03:14:20 +0800940
Alison Schofield29b1b612015-10-06 14:40:58 -0700941 if (!strcasecmp(ext, "RSSI")) {
Ali Baharc6dc0012011-09-04 03:14:20 +0800942 /*Return received signal strength indicator in -db for */
943 /* current AP */
944 /*<ssid> Rssi xx */
945 struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
946 struct wlan_network *pcur_network = &pmlmepriv->cur_network;
947 /*static u8 xxxx; */
Luis de Bethencourt1ca96882015-10-19 18:14:29 +0100948 if (check_fwstate(pmlmepriv, _FW_LINKED)) {
Ali Baharc6dc0012011-09-04 03:14:20 +0800949 sprintf(ext, "%s rssi %d",
950 pcur_network->network.Ssid.Ssid,
951 /*(xxxx=xxxx+10) */
952 ((padapter->recvpriv.fw_rssi)>>1)-95
953 /*pcur_network->network.Rssi */
954 );
955 } else {
956 sprintf(ext, "OK");
957 }
Alison Schofield29b1b612015-10-06 14:40:58 -0700958 } else if (!strcasecmp(ext, "LINKSPEED")) {
Ali Baharc6dc0012011-09-04 03:14:20 +0800959 /*Return link speed in MBPS */
960 /*LinkSpeed xx */
961 union iwreq_data wrqd;
962 int ret_inner;
963 int mbps;
964
965 ret_inner = r8711_wx_get_rate(dev, info, &wrqd, extra);
Alison Schofield29b1b612015-10-06 14:40:58 -0700966 if (ret_inner != 0)
Ali Baharc6dc0012011-09-04 03:14:20 +0800967 mbps = 0;
968 else
969 mbps = wrqd.bitrate.value / 1000000;
970 sprintf(ext, "LINKSPEED %d", mbps);
Alison Schofield29b1b612015-10-06 14:40:58 -0700971 } else if (!strcasecmp(ext, "MACADDR")) {
Ali Baharc6dc0012011-09-04 03:14:20 +0800972 /*Return mac address of the station */
Andy Shevchenko87fa05e2013-07-10 17:27:21 +0300973 /* Macaddr = xx:xx:xx:xx:xx:xx */
974 sprintf(ext, "MACADDR = %pM", dev->dev_addr);
Alison Schofield29b1b612015-10-06 14:40:58 -0700975 } else if (!strcasecmp(ext, "SCAN-ACTIVE")) {
Ali Baharc6dc0012011-09-04 03:14:20 +0800976 /*Set scan type to active */
977 /*OK if successful */
978 struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
Tapasweni Pathak02a29d22014-09-24 16:34:56 +0530979
Ali Baharc6dc0012011-09-04 03:14:20 +0800980 pmlmepriv->passive_mode = 1;
981 sprintf(ext, "OK");
Alison Schofield29b1b612015-10-06 14:40:58 -0700982 } else if (!strcasecmp(ext, "SCAN-PASSIVE")) {
Ali Baharc6dc0012011-09-04 03:14:20 +0800983 /*Set scan type to passive */
984 /*OK if successful */
985 struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
Tapasweni Pathak02a29d22014-09-24 16:34:56 +0530986
Ali Baharc6dc0012011-09-04 03:14:20 +0800987 pmlmepriv->passive_mode = 0;
988 sprintf(ext, "OK");
Alison Schofield29b1b612015-10-06 14:40:58 -0700989 } else if (!strncmp(ext, "DCE-E", 5)) {
Ali Baharc6dc0012011-09-04 03:14:20 +0800990 /*Set scan type to passive */
991 /*OK if successful */
992 r8712_disconnectCtrlEx_cmd(padapter
993 , 1 /*u32 enableDrvCtrl */
994 , 5 /*u32 tryPktCnt */
995 , 100 /*u32 tryPktInterval */
996 , 5000 /*u32 firstStageTO */
997 );
998 sprintf(ext, "OK");
Alison Schofield29b1b612015-10-06 14:40:58 -0700999 } else if (!strncmp(ext, "DCE-D", 5)) {
Ali Baharc6dc0012011-09-04 03:14:20 +08001000 /*Set scan type to passive */
1001 /*OK if successfu */
1002 r8712_disconnectCtrlEx_cmd(padapter
1003 , 0 /*u32 enableDrvCtrl */
1004 , 5 /*u32 tryPktCnt */
1005 , 100 /*u32 tryPktInterval */
1006 , 5000 /*u32 firstStageTO */
1007 );
1008 sprintf(ext, "OK");
1009 } else {
Przemo Firszt87a573a2012-12-10 23:21:21 +00001010 netdev_info(dev, "r8712u: %s: unknown Command %s.\n",
1011 __func__, ext);
Ali Baharc6dc0012011-09-04 03:14:20 +08001012 goto FREE_EXT;
1013 }
1014 if (copy_to_user(dwrq->pointer, ext,
1015 min(dwrq->length, (__u16)(strlen(ext)+1))))
1016 ret = -EFAULT;
1017
1018FREE_EXT:
Larry Finger2865d422010-08-20 10:15:30 -05001019 kfree(ext);
1020 return ret;
1021}
1022
1023/* set bssid flow
1024 * s1. set_802_11_infrastructure_mode()
1025 * s2. set_802_11_authentication_mode()
1026 * s3. set_802_11_encryption_mode()
1027 * s4. set_802_11_bssid()
Ali Bahard1661df2011-07-12 23:10:55 +08001028 *
1029 * This function intends to handle the Set AP command, which specifies the
1030 * MAC# of a preferred Access Point.
1031 * Currently, the request comes via Wireless Extensions' SIOCSIWAP ioctl.
1032 *
Justin P. Mattockbe10ac22012-05-07 07:38:22 -07001033 * For this operation to succeed, there is no need for the interface to be up.
Ali Bahard1661df2011-07-12 23:10:55 +08001034 *
Larry Finger2865d422010-08-20 10:15:30 -05001035 */
1036static int r8711_wx_set_wap(struct net_device *dev,
1037 struct iw_request_info *info,
1038 union iwreq_data *awrq,
1039 char *extra)
1040{
1041 int ret = -EINPROGRESS;
Julia Lawall8f47c282015-03-29 14:54:12 +02001042 struct _adapter *padapter = netdev_priv(dev);
Larry Finger2865d422010-08-20 10:15:30 -05001043 struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
1044 struct __queue *queue = &pmlmepriv->scanned_queue;
1045 struct sockaddr *temp = (struct sockaddr *)awrq;
1046 unsigned long irqL;
1047 struct list_head *phead;
1048 u8 *dst_bssid;
1049 struct wlan_network *pnetwork = NULL;
1050 enum NDIS_802_11_AUTHENTICATION_MODE authmode;
1051
Luis de Bethencourt1ca96882015-10-19 18:14:29 +01001052 if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY))
Ali Bahar2192e602011-09-04 03:14:24 +08001053 return -EBUSY;
Luis de Bethencourt1ca96882015-10-19 18:14:29 +01001054 if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING))
Larry Finger2865d422010-08-20 10:15:30 -05001055 return ret;
1056 if (temp->sa_family != ARPHRD_ETHER)
1057 return -EINVAL;
1058 authmode = padapter->securitypriv.ndisauthtype;
1059 spin_lock_irqsave(&queue->lock, irqL);
James A Shackleforde99a4282014-06-24 22:52:39 -04001060 phead = &queue->queue;
James A Shackleford849fb0a2014-06-24 22:52:38 -04001061 pmlmepriv->pscanned = phead->next;
Larry Finger2865d422010-08-20 10:15:30 -05001062 while (1) {
Luis de Bethencourt1ca96882015-10-19 18:14:29 +01001063 if (end_of_queue_search(phead, pmlmepriv->pscanned))
Larry Finger2865d422010-08-20 10:15:30 -05001064 break;
1065 pnetwork = LIST_CONTAINOR(pmlmepriv->pscanned,
1066 struct wlan_network, list);
James A Shackleford849fb0a2014-06-24 22:52:38 -04001067 pmlmepriv->pscanned = pmlmepriv->pscanned->next;
Larry Finger2865d422010-08-20 10:15:30 -05001068 dst_bssid = pnetwork->network.MacAddress;
1069 if (!memcmp(dst_bssid, temp->sa_data, ETH_ALEN)) {
Ali Bahar2192e602011-09-04 03:14:24 +08001070 r8712_set_802_11_infrastructure_mode(padapter,
1071 pnetwork->network.InfrastructureMode);
Larry Finger2865d422010-08-20 10:15:30 -05001072 break;
1073 }
1074 }
1075 spin_unlock_irqrestore(&queue->lock, irqL);
1076 if (!ret) {
Luis de Bethencourt168a2c12015-10-19 18:15:29 +01001077 if (!r8712_set_802_11_authentication_mode(padapter, authmode)) {
Ali Bahar2192e602011-09-04 03:14:24 +08001078 ret = -ENOMEM;
Luis de Bethencourt168a2c12015-10-19 18:15:29 +01001079 } else {
Larry Finger2865d422010-08-20 10:15:30 -05001080 if (!r8712_set_802_11_bssid(padapter, temp->sa_data))
1081 ret = -1;
1082 }
1083 }
1084 return ret;
1085}
1086
1087static int r8711_wx_get_wap(struct net_device *dev,
1088 struct iw_request_info *info,
1089 union iwreq_data *wrqu, char *extra)
1090{
Julia Lawall8f47c282015-03-29 14:54:12 +02001091 struct _adapter *padapter = netdev_priv(dev);
Larry Finger2865d422010-08-20 10:15:30 -05001092 struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
Joshua Clayton44367872015-08-05 17:17:18 -07001093 struct wlan_bssid_ex *pcur_bss = &pmlmepriv->cur_network.network;
Larry Finger2865d422010-08-20 10:15:30 -05001094
1095 wrqu->ap_addr.sa_family = ARPHRD_ETHER;
Cyril Roelandt2df29e72012-12-11 01:20:48 +01001096 if (check_fwstate(pmlmepriv, _FW_LINKED | WIFI_ADHOC_MASTER_STATE |
1097 WIFI_AP_STATE))
Haneen Mohammede0e982b2015-03-16 18:41:31 +03001098 ether_addr_copy(wrqu->ap_addr.sa_data, pcur_bss->MacAddress);
Cyril Roelandt2df29e72012-12-11 01:20:48 +01001099 else
Aya Mahfouz22905b82015-03-04 09:00:02 +02001100 eth_zero_addr(wrqu->ap_addr.sa_data);
Larry Finger2865d422010-08-20 10:15:30 -05001101 return 0;
1102}
1103
1104static int r871x_wx_set_mlme(struct net_device *dev,
1105 struct iw_request_info *info,
1106 union iwreq_data *wrqu, char *extra)
1107{
1108 int ret = 0;
Julia Lawall8f47c282015-03-29 14:54:12 +02001109 struct _adapter *padapter = netdev_priv(dev);
Larry Finger2865d422010-08-20 10:15:30 -05001110 struct iw_mlme *mlme = (struct iw_mlme *) extra;
1111
1112 if (mlme == NULL)
1113 return -1;
Larry Finger2865d422010-08-20 10:15:30 -05001114 switch (mlme->cmd) {
1115 case IW_MLME_DEAUTH:
1116 if (!r8712_set_802_11_disassociate(padapter))
1117 ret = -1;
1118 break;
1119 case IW_MLME_DISASSOC:
1120 if (!r8712_set_802_11_disassociate(padapter))
1121 ret = -1;
1122 break;
1123 default:
1124 return -EOPNOTSUPP;
1125 }
1126 return ret;
1127}
1128
Ali Bahard1661df2011-07-12 23:10:55 +08001129/**
1130 *
1131 * This function intends to handle the Set Scan command.
1132 * Currently, the request comes via Wireless Extensions' SIOCSIWSCAN ioctl.
1133 *
1134 * For this operation to succeed, the interface is brought Up beforehand.
1135 *
1136 */
Larry Finger2865d422010-08-20 10:15:30 -05001137static int r8711_wx_set_scan(struct net_device *dev,
1138 struct iw_request_info *a,
1139 union iwreq_data *wrqu, char *extra)
1140{
Julia Lawall8f47c282015-03-29 14:54:12 +02001141 struct _adapter *padapter = netdev_priv(dev);
Larry Finger2865d422010-08-20 10:15:30 -05001142 struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
1143 u8 status = true;
1144
Luis de Bethencourt1ca96882015-10-19 18:14:29 +01001145 if (padapter->bDriverStopped) {
Przemo Firszt87a573a2012-12-10 23:21:21 +00001146 netdev_info(dev, "In %s: bDriverStopped=%d\n",
1147 __func__, padapter->bDriverStopped);
Larry Finger2865d422010-08-20 10:15:30 -05001148 return -1;
1149 }
Luis de Bethencourt1ca96882015-10-19 18:14:29 +01001150 if (!padapter->bup)
Ali Bahar2192e602011-09-04 03:14:24 +08001151 return -ENETDOWN;
Luis de Bethencourt1ca96882015-10-19 18:14:29 +01001152 if (!padapter->hw_init_completed)
Larry Finger2865d422010-08-20 10:15:30 -05001153 return -1;
1154 if ((check_fwstate(pmlmepriv, _FW_UNDER_SURVEY|_FW_UNDER_LINKING)) ||
Luis de Bethencourt1ca96882015-10-19 18:14:29 +01001155 (pmlmepriv->sitesurveyctrl.traffic_busy))
Larry Finger2865d422010-08-20 10:15:30 -05001156 return 0;
1157 if (wrqu->data.length == sizeof(struct iw_scan_req)) {
1158 struct iw_scan_req *req = (struct iw_scan_req *)extra;
Tapasweni Pathak02a29d22014-09-24 16:34:56 +05301159
Larry Finger2865d422010-08-20 10:15:30 -05001160 if (wrqu->data.flags & IW_SCAN_THIS_ESSID) {
1161 struct ndis_802_11_ssid ssid;
1162 unsigned long irqL;
Przemo Firszt0024a1e2012-12-10 23:21:22 +00001163 u32 len = min_t(u8, req->essid_len, IW_ESSID_MAX_SIZE);
Tapasweni Pathak02a29d22014-09-24 16:34:56 +05301164
Larry Finger2865d422010-08-20 10:15:30 -05001165 memset((unsigned char *)&ssid, 0,
1166 sizeof(struct ndis_802_11_ssid));
1167 memcpy(ssid.Ssid, req->essid, len);
1168 ssid.SsidLength = len;
1169 spin_lock_irqsave(&pmlmepriv->lock, irqL);
1170 if ((check_fwstate(pmlmepriv, _FW_UNDER_SURVEY |
1171 _FW_UNDER_LINKING)) ||
Luis de Bethencourt1ca96882015-10-19 18:14:29 +01001172 (pmlmepriv->sitesurveyctrl.traffic_busy)) {
Larry Finger2865d422010-08-20 10:15:30 -05001173 if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING))
1174 status = false;
Luis de Bethencourt168a2c12015-10-19 18:15:29 +01001175 } else {
Larry Finger2865d422010-08-20 10:15:30 -05001176 status = r8712_sitesurvey_cmd(padapter, &ssid);
Luis de Bethencourt168a2c12015-10-19 18:15:29 +01001177 }
Larry Finger2865d422010-08-20 10:15:30 -05001178 spin_unlock_irqrestore(&pmlmepriv->lock, irqL);
1179 }
Luis de Bethencourt168a2c12015-10-19 18:15:29 +01001180 } else {
Larry Finger2865d422010-08-20 10:15:30 -05001181 status = r8712_set_802_11_bssid_list_scan(padapter);
Luis de Bethencourt168a2c12015-10-19 18:15:29 +01001182 }
Luis de Bethencourt1ca96882015-10-19 18:14:29 +01001183 if (!status)
Larry Finger2865d422010-08-20 10:15:30 -05001184 return -1;
1185 return 0;
1186}
1187
1188static int r8711_wx_get_scan(struct net_device *dev,
1189 struct iw_request_info *a,
1190 union iwreq_data *wrqu, char *extra)
1191{
Julia Lawall8f47c282015-03-29 14:54:12 +02001192 struct _adapter *padapter = netdev_priv(dev);
Larry Finger2865d422010-08-20 10:15:30 -05001193 struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
1194 struct __queue *queue = &pmlmepriv->scanned_queue;
1195 struct wlan_network *pnetwork = NULL;
1196 unsigned long irqL;
1197 struct list_head *plist, *phead;
1198 char *ev = extra;
1199 char *stop = ev + wrqu->data.length;
1200 u32 ret = 0, cnt = 0;
1201
1202 if (padapter->bDriverStopped)
1203 return -EINVAL;
1204 while (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY|_FW_UNDER_LINKING)) {
1205 msleep(30);
1206 cnt++;
Ali Baharc6dc0012011-09-04 03:14:20 +08001207 if (cnt > 100)
Larry Finger2865d422010-08-20 10:15:30 -05001208 break;
1209 }
1210 spin_lock_irqsave(&queue->lock, irqL);
James A Shackleforde99a4282014-06-24 22:52:39 -04001211 phead = &queue->queue;
James A Shackleford849fb0a2014-06-24 22:52:38 -04001212 plist = phead->next;
Larry Finger2865d422010-08-20 10:15:30 -05001213 while (1) {
Luis de Bethencourt1ca96882015-10-19 18:14:29 +01001214 if (end_of_queue_search(phead, plist))
Larry Finger2865d422010-08-20 10:15:30 -05001215 break;
1216 if ((stop - ev) < SCAN_ITEM_SIZE) {
1217 ret = -E2BIG;
1218 break;
1219 }
1220 pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
1221 ev = translate_scan(padapter, a, pnetwork, ev, stop);
James A Shackleford849fb0a2014-06-24 22:52:38 -04001222 plist = plist->next;
Larry Finger2865d422010-08-20 10:15:30 -05001223 }
1224 spin_unlock_irqrestore(&queue->lock, irqL);
1225 wrqu->data.length = ev - extra;
1226 wrqu->data.flags = 0;
1227 return ret;
1228}
1229
1230/* set ssid flow
1231 * s1. set_802_11_infrastructure_mode()
1232 * s2. set_802_11_authenticaion_mode()
1233 * s3. set_802_11_encryption_mode()
1234 * s4. set_802_11_ssid()
Ali Bahard1661df2011-07-12 23:10:55 +08001235 *
1236 * This function intends to handle the Set ESSID command.
1237 * Currently, the request comes via the Wireless Extensions' SIOCSIWESSID ioctl.
1238 *
1239 * For this operation to succeed, there is no need for the interface to be Up.
1240 *
Larry Finger2865d422010-08-20 10:15:30 -05001241 */
1242static int r8711_wx_set_essid(struct net_device *dev,
1243 struct iw_request_info *a,
1244 union iwreq_data *wrqu, char *extra)
1245{
Julia Lawall8f47c282015-03-29 14:54:12 +02001246 struct _adapter *padapter = netdev_priv(dev);
Larry Finger2865d422010-08-20 10:15:30 -05001247 struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
1248 struct __queue *queue = &pmlmepriv->scanned_queue;
1249 struct wlan_network *pnetwork = NULL;
1250 enum NDIS_802_11_AUTHENTICATION_MODE authmode;
1251 struct ndis_802_11_ssid ndis_ssid;
1252 u8 *dst_ssid, *src_ssid;
1253 struct list_head *phead;
1254 u32 len;
1255
Larry Finger2865d422010-08-20 10:15:30 -05001256 if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY))
Ali Bahar2192e602011-09-04 03:14:24 +08001257 return -EBUSY;
Larry Finger2865d422010-08-20 10:15:30 -05001258 if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING))
1259 return 0;
1260 if (wrqu->essid.length > IW_ESSID_MAX_SIZE)
1261 return -E2BIG;
1262 authmode = padapter->securitypriv.ndisauthtype;
1263 if (wrqu->essid.flags && wrqu->essid.length) {
1264 len = (wrqu->essid.length < IW_ESSID_MAX_SIZE) ?
1265 wrqu->essid.length : IW_ESSID_MAX_SIZE;
1266 memset(&ndis_ssid, 0, sizeof(struct ndis_802_11_ssid));
1267 ndis_ssid.SsidLength = len;
1268 memcpy(ndis_ssid.Ssid, extra, len);
1269 src_ssid = ndis_ssid.Ssid;
James A Shackleforde99a4282014-06-24 22:52:39 -04001270 phead = &queue->queue;
James A Shackleford849fb0a2014-06-24 22:52:38 -04001271 pmlmepriv->pscanned = phead->next;
Larry Finger2865d422010-08-20 10:15:30 -05001272 while (1) {
1273 if (end_of_queue_search(phead, pmlmepriv->pscanned))
1274 break;
1275 pnetwork = LIST_CONTAINOR(pmlmepriv->pscanned,
1276 struct wlan_network, list);
James A Shackleford849fb0a2014-06-24 22:52:38 -04001277 pmlmepriv->pscanned = pmlmepriv->pscanned->next;
Larry Finger2865d422010-08-20 10:15:30 -05001278 dst_ssid = pnetwork->network.Ssid.Ssid;
1279 if ((!memcmp(dst_ssid, src_ssid, ndis_ssid.SsidLength))
1280 && (pnetwork->network.Ssid.SsidLength ==
1281 ndis_ssid.SsidLength)) {
Ali Baharc6dc0012011-09-04 03:14:20 +08001282 if (check_fwstate(pmlmepriv,
1283 WIFI_ADHOC_STATE)) {
1284 if (pnetwork->network.
1285 InfrastructureMode
1286 !=
1287 padapter->mlmepriv.
1288 cur_network.network.
1289 InfrastructureMode)
1290 continue;
1291 }
1292
Ali Bahar2192e602011-09-04 03:14:24 +08001293 r8712_set_802_11_infrastructure_mode(
Larry Finger2865d422010-08-20 10:15:30 -05001294 padapter,
Ali Bahar2192e602011-09-04 03:14:24 +08001295 pnetwork->network.InfrastructureMode);
Larry Finger2865d422010-08-20 10:15:30 -05001296 break;
1297 }
1298 }
1299 r8712_set_802_11_authentication_mode(padapter, authmode);
1300 r8712_set_802_11_ssid(padapter, &ndis_ssid);
1301 }
1302 return -EINPROGRESS;
1303}
1304
1305static int r8711_wx_get_essid(struct net_device *dev,
1306 struct iw_request_info *a,
1307 union iwreq_data *wrqu, char *extra)
1308{
Julia Lawall8f47c282015-03-29 14:54:12 +02001309 struct _adapter *padapter = netdev_priv(dev);
Larry Finger2865d422010-08-20 10:15:30 -05001310 struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
Joshua Clayton44367872015-08-05 17:17:18 -07001311 struct wlan_bssid_ex *pcur_bss = &pmlmepriv->cur_network.network;
Larry Finger2865d422010-08-20 10:15:30 -05001312 u32 len, ret = 0;
1313
1314 if (check_fwstate(pmlmepriv, _FW_LINKED|WIFI_ADHOC_MASTER_STATE)) {
1315 len = pcur_bss->Ssid.SsidLength;
1316 wrqu->essid.length = len;
1317 memcpy(extra, pcur_bss->Ssid.Ssid, len);
1318 wrqu->essid.flags = 1;
Ali Bahar2192e602011-09-04 03:14:24 +08001319 } else {
1320 ret = -ENOLINK;
1321 }
Larry Finger2865d422010-08-20 10:15:30 -05001322 return ret;
1323}
1324
1325static int r8711_wx_set_rate(struct net_device *dev,
1326 struct iw_request_info *a,
1327 union iwreq_data *wrqu, char *extra)
1328{
Julia Lawall8f47c282015-03-29 14:54:12 +02001329 struct _adapter *padapter = netdev_priv(dev);
Larry Finger2865d422010-08-20 10:15:30 -05001330 u32 target_rate = wrqu->bitrate.value;
1331 u32 fixed = wrqu->bitrate.fixed;
1332 u32 ratevalue = 0;
1333 u8 datarates[NumRates];
1334 u8 mpdatarate[NumRates] = {11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0xff};
1335 int i, ret = 0;
1336
1337 if (target_rate == -1) {
1338 ratevalue = 11;
1339 goto set_rate;
1340 }
1341 target_rate = target_rate / 100000;
1342 switch (target_rate) {
1343 case 10:
1344 ratevalue = 0;
1345 break;
1346 case 20:
1347 ratevalue = 1;
1348 break;
1349 case 55:
1350 ratevalue = 2;
1351 break;
1352 case 60:
1353 ratevalue = 3;
1354 break;
1355 case 90:
1356 ratevalue = 4;
1357 break;
1358 case 110:
1359 ratevalue = 5;
1360 break;
1361 case 120:
1362 ratevalue = 6;
1363 break;
1364 case 180:
1365 ratevalue = 7;
1366 break;
1367 case 240:
1368 ratevalue = 8;
1369 break;
1370 case 360:
1371 ratevalue = 9;
1372 break;
1373 case 480:
1374 ratevalue = 10;
1375 break;
1376 case 540:
1377 ratevalue = 11;
1378 break;
1379 default:
1380 ratevalue = 11;
1381 break;
1382 }
1383set_rate:
1384 for (i = 0; i < NumRates; i++) {
1385 if (ratevalue == mpdatarate[i]) {
1386 datarates[i] = mpdatarate[i];
1387 if (fixed == 0)
1388 break;
Luis de Bethencourt168a2c12015-10-19 18:15:29 +01001389 } else {
Larry Finger2865d422010-08-20 10:15:30 -05001390 datarates[i] = 0xff;
Luis de Bethencourt168a2c12015-10-19 18:15:29 +01001391 }
Larry Finger2865d422010-08-20 10:15:30 -05001392 }
1393 if (r8712_setdatarate_cmd(padapter, datarates) != _SUCCESS)
Ali Bahar2192e602011-09-04 03:14:24 +08001394 ret = -ENOMEM;
Larry Finger2865d422010-08-20 10:15:30 -05001395 return ret;
1396}
1397
1398static int r8711_wx_get_rate(struct net_device *dev,
1399 struct iw_request_info *info,
1400 union iwreq_data *wrqu, char *extra)
1401{
Julia Lawall8f47c282015-03-29 14:54:12 +02001402 struct _adapter *padapter = netdev_priv(dev);
Larry Finger2865d422010-08-20 10:15:30 -05001403 struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
Joshua Clayton44367872015-08-05 17:17:18 -07001404 struct wlan_bssid_ex *pcur_bss = &pmlmepriv->cur_network.network;
Larry Finger2865d422010-08-20 10:15:30 -05001405 struct ieee80211_ht_cap *pht_capie;
Ali Baharc6dc0012011-09-04 03:14:20 +08001406 unsigned char rf_type = padapter->registrypriv.rf_config;
Larry Finger2865d422010-08-20 10:15:30 -05001407 int i;
1408 u8 *p;
1409 u16 rate, max_rate = 0, ht_cap = false;
1410 u32 ht_ielen = 0;
1411 u8 bw_40MHz = 0, short_GI = 0;
1412 u16 mcs_rate = 0;
1413
1414 i = 0;
1415 if (check_fwstate(pmlmepriv, _FW_LINKED|WIFI_ADHOC_MASTER_STATE)) {
1416 p = r8712_get_ie(&pcur_bss->IEs[12],
1417 _HT_CAPABILITY_IE_, &ht_ielen,
1418 pcur_bss->IELength - 12);
1419 if (p && ht_ielen > 0) {
1420 ht_cap = true;
1421 pht_capie = (struct ieee80211_ht_cap *)(p + 2);
Max Perepelitsyn0636b462015-01-02 14:08:08 +06001422 memcpy(&mcs_rate, pht_capie->supp_mcs_set, 2);
Larry Finger2865d422010-08-20 10:15:30 -05001423 bw_40MHz = (pht_capie->cap_info &
1424 IEEE80211_HT_CAP_SUP_WIDTH) ? 1 : 0;
1425 short_GI = (pht_capie->cap_info &
1426 (IEEE80211_HT_CAP_SGI_20 |
1427 IEEE80211_HT_CAP_SGI_40)) ? 1 : 0;
1428 }
Joshua Clayton7fb539e2015-08-05 17:17:21 -07001429 while ((pcur_bss->rates[i] != 0) &&
1430 (pcur_bss->rates[i] != 0xFF)) {
1431 rate = pcur_bss->rates[i] & 0x7F;
Larry Finger2865d422010-08-20 10:15:30 -05001432 if (rate > max_rate)
1433 max_rate = rate;
1434 wrqu->bitrate.fixed = 0; /* no auto select */
1435 wrqu->bitrate.value = rate*500000;
1436 i++;
1437 }
Luis de Bethencourt1ca96882015-10-19 18:14:29 +01001438 if (ht_cap) {
Ali Baharc6dc0012011-09-04 03:14:20 +08001439 if (mcs_rate & 0x8000 /* MCS15 */
1440 &&
Alison Schofield29b1b612015-10-06 14:40:58 -07001441 rf_type == RTL8712_RF_2T2R)
Larry Finger2865d422010-08-20 10:15:30 -05001442 max_rate = (bw_40MHz) ? ((short_GI) ? 300 :
1443 270) : ((short_GI) ? 144 : 130);
Larry Finger2865d422010-08-20 10:15:30 -05001444 else /* default MCS7 */
1445 max_rate = (bw_40MHz) ? ((short_GI) ? 150 :
1446 135) : ((short_GI) ? 72 : 65);
1447 max_rate *= 2; /* Mbps/2 */
Larry Finger2865d422010-08-20 10:15:30 -05001448 }
Rickard Strandqvist3ae70742014-06-15 19:20:58 +02001449 wrqu->bitrate.value = max_rate * 500000;
Luis de Bethencourt168a2c12015-10-19 18:15:29 +01001450 } else {
Ali Bahar2192e602011-09-04 03:14:24 +08001451 return -ENOLINK;
Luis de Bethencourt168a2c12015-10-19 18:15:29 +01001452 }
Larry Finger2865d422010-08-20 10:15:30 -05001453 return 0;
1454}
1455
1456static int r8711_wx_get_rts(struct net_device *dev,
1457 struct iw_request_info *info,
1458 union iwreq_data *wrqu, char *extra)
1459{
Julia Lawall8f47c282015-03-29 14:54:12 +02001460 struct _adapter *padapter = netdev_priv(dev);
Larry Finger2865d422010-08-20 10:15:30 -05001461
1462 wrqu->rts.value = padapter->registrypriv.rts_thresh;
1463 wrqu->rts.fixed = 0; /* no auto select */
1464 return 0;
1465}
1466
1467static int r8711_wx_set_frag(struct net_device *dev,
1468 struct iw_request_info *info,
1469 union iwreq_data *wrqu, char *extra)
1470{
Julia Lawall8f47c282015-03-29 14:54:12 +02001471 struct _adapter *padapter = netdev_priv(dev);
Larry Finger2865d422010-08-20 10:15:30 -05001472
Luis de Bethencourt168a2c12015-10-19 18:15:29 +01001473 if (wrqu->frag.disabled) {
Larry Finger2865d422010-08-20 10:15:30 -05001474 padapter->xmitpriv.frag_len = MAX_FRAG_THRESHOLD;
Luis de Bethencourt168a2c12015-10-19 18:15:29 +01001475 } else {
Larry Finger2865d422010-08-20 10:15:30 -05001476 if (wrqu->frag.value < MIN_FRAG_THRESHOLD ||
1477 wrqu->frag.value > MAX_FRAG_THRESHOLD)
1478 return -EINVAL;
1479 padapter->xmitpriv.frag_len = wrqu->frag.value & ~0x1;
1480 }
1481 return 0;
1482}
1483
1484static int r8711_wx_get_frag(struct net_device *dev,
1485 struct iw_request_info *info,
1486 union iwreq_data *wrqu, char *extra)
1487{
Julia Lawall8f47c282015-03-29 14:54:12 +02001488 struct _adapter *padapter = netdev_priv(dev);
Larry Finger2865d422010-08-20 10:15:30 -05001489
1490 wrqu->frag.value = padapter->xmitpriv.frag_len;
1491 wrqu->frag.fixed = 0; /* no auto select */
1492 return 0;
1493}
1494
1495static int r8711_wx_get_retry(struct net_device *dev,
1496 struct iw_request_info *info,
1497 union iwreq_data *wrqu, char *extra)
1498{
1499 wrqu->retry.value = 7;
1500 wrqu->retry.fixed = 0; /* no auto select */
1501 wrqu->retry.disabled = 1;
1502 return 0;
1503}
1504
1505static int r8711_wx_set_enc(struct net_device *dev,
1506 struct iw_request_info *info,
1507 union iwreq_data *wrqu, char *keybuf)
1508{
1509 u32 key;
1510 u32 keyindex_provided;
1511 struct NDIS_802_11_WEP wep;
1512 enum NDIS_802_11_AUTHENTICATION_MODE authmode;
1513 struct iw_point *erq = &(wrqu->encoding);
Julia Lawall8f47c282015-03-29 14:54:12 +02001514 struct _adapter *padapter = netdev_priv(dev);
Larry Finger2865d422010-08-20 10:15:30 -05001515
1516 key = erq->flags & IW_ENCODE_INDEX;
1517 memset(&wep, 0, sizeof(struct NDIS_802_11_WEP));
1518 if (erq->flags & IW_ENCODE_DISABLED) {
Przemo Firszt87a573a2012-12-10 23:21:21 +00001519 netdev_info(dev, "r8712u: %s: EncryptionDisabled\n", __func__);
Larry Finger2865d422010-08-20 10:15:30 -05001520 padapter->securitypriv.ndisencryptstatus =
1521 Ndis802_11EncryptionDisabled;
1522 padapter->securitypriv.PrivacyAlgrthm = _NO_PRIVACY_;
1523 padapter->securitypriv.XGrpPrivacy = _NO_PRIVACY_;
1524 padapter->securitypriv.AuthAlgrthm = 0; /* open system */
1525 authmode = Ndis802_11AuthModeOpen;
1526 padapter->securitypriv.ndisauthtype = authmode;
1527 return 0;
1528 }
1529 if (key) {
1530 if (key > WEP_KEYS)
1531 return -EINVAL;
1532 key--;
1533 keyindex_provided = 1;
1534 } else {
1535 keyindex_provided = 0;
1536 key = padapter->securitypriv.PrivacyKeyIndex;
1537 }
1538 /* set authentication mode */
1539 if (erq->flags & IW_ENCODE_OPEN) {
Przemo Firszt87a573a2012-12-10 23:21:21 +00001540 netdev_info(dev, "r8712u: %s: IW_ENCODE_OPEN\n", __func__);
Larry Finger2865d422010-08-20 10:15:30 -05001541 padapter->securitypriv.ndisencryptstatus =
1542 Ndis802_11Encryption1Enabled;
1543 padapter->securitypriv.AuthAlgrthm = 0; /* open system */
1544 padapter->securitypriv.PrivacyAlgrthm = _NO_PRIVACY_;
1545 padapter->securitypriv.XGrpPrivacy = _NO_PRIVACY_;
1546 authmode = Ndis802_11AuthModeOpen;
1547 padapter->securitypriv.ndisauthtype = authmode;
1548 } else if (erq->flags & IW_ENCODE_RESTRICTED) {
Tapasweni Pathak57b66862014-09-21 06:42:21 +05301549 netdev_info(dev,
1550 "r8712u: %s: IW_ENCODE_RESTRICTED\n", __func__);
Larry Finger2865d422010-08-20 10:15:30 -05001551 padapter->securitypriv.ndisencryptstatus =
1552 Ndis802_11Encryption1Enabled;
1553 padapter->securitypriv.AuthAlgrthm = 1; /* shared system */
1554 padapter->securitypriv.PrivacyAlgrthm = _WEP40_;
1555 padapter->securitypriv.XGrpPrivacy = _WEP40_;
1556 authmode = Ndis802_11AuthModeShared;
1557 padapter->securitypriv.ndisauthtype = authmode;
1558 } else {
1559 padapter->securitypriv.ndisencryptstatus =
1560 Ndis802_11Encryption1Enabled;
1561 padapter->securitypriv.AuthAlgrthm = 0; /* open system */
1562 padapter->securitypriv.PrivacyAlgrthm = _NO_PRIVACY_;
1563 padapter->securitypriv.XGrpPrivacy = _NO_PRIVACY_;
1564 authmode = Ndis802_11AuthModeOpen;
1565 padapter->securitypriv.ndisauthtype = authmode;
1566 }
1567 wep.KeyIndex = key;
1568 if (erq->length > 0) {
1569 wep.KeyLength = erq->length <= 5 ? 5 : 13;
1570 wep.Length = wep.KeyLength +
1571 FIELD_OFFSET(struct NDIS_802_11_WEP, KeyMaterial);
1572 } else {
Thomas Cort77e73e82013-10-01 11:26:55 -04001573 wep.KeyLength = 0;
Larry Finger2865d422010-08-20 10:15:30 -05001574 if (keyindex_provided == 1) { /* set key_id only, no given
Punit Varad32c16d2015-10-14 23:55:54 +05301575 * KeyMaterial(erq->length==0).
1576 */
Larry Finger2865d422010-08-20 10:15:30 -05001577 padapter->securitypriv.PrivacyKeyIndex = key;
1578 switch (padapter->securitypriv.DefKeylen[key]) {
1579 case 5:
1580 padapter->securitypriv.PrivacyAlgrthm =
1581 _WEP40_;
1582 break;
1583 case 13:
1584 padapter->securitypriv.PrivacyAlgrthm =
1585 _WEP104_;
1586 break;
1587 default:
1588 padapter->securitypriv.PrivacyAlgrthm =
1589 _NO_PRIVACY_;
1590 break;
1591 }
1592 return 0;
1593 }
1594 }
1595 wep.KeyIndex |= 0x80000000; /* transmit key */
1596 memcpy(wep.KeyMaterial, keybuf, wep.KeyLength);
1597 if (r8712_set_802_11_add_wep(padapter, &wep) == _FAIL)
1598 return -EOPNOTSUPP;
1599 return 0;
1600}
1601
1602static int r8711_wx_get_enc(struct net_device *dev,
1603 struct iw_request_info *info,
1604 union iwreq_data *wrqu, char *keybuf)
1605{
1606 uint key, ret = 0;
Julia Lawall8f47c282015-03-29 14:54:12 +02001607 struct _adapter *padapter = netdev_priv(dev);
Larry Finger2865d422010-08-20 10:15:30 -05001608 struct iw_point *erq = &(wrqu->encoding);
1609 struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
1610
Luis de Bethencourt1ca96882015-10-19 18:14:29 +01001611 if (!check_fwstate(pmlmepriv, _FW_LINKED)) {
Larry Finger2865d422010-08-20 10:15:30 -05001612 if (!check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) {
1613 erq->length = 0;
1614 erq->flags |= IW_ENCODE_DISABLED;
1615 return 0;
1616 }
1617 }
1618 key = erq->flags & IW_ENCODE_INDEX;
1619 if (key) {
1620 if (key > WEP_KEYS)
1621 return -EINVAL;
1622 key--;
1623 } else {
1624 key = padapter->securitypriv.PrivacyKeyIndex;
1625 }
1626 erq->flags = key + 1;
1627 switch (padapter->securitypriv.ndisencryptstatus) {
1628 case Ndis802_11EncryptionNotSupported:
1629 case Ndis802_11EncryptionDisabled:
1630 erq->length = 0;
1631 erq->flags |= IW_ENCODE_DISABLED;
1632 break;
1633 case Ndis802_11Encryption1Enabled:
1634 erq->length = padapter->securitypriv.DefKeylen[key];
1635 if (erq->length) {
1636 memcpy(keybuf, padapter->securitypriv.DefKey[
1637 key].skey, padapter->securitypriv.
1638 DefKeylen[key]);
1639 erq->flags |= IW_ENCODE_ENABLED;
1640 if (padapter->securitypriv.ndisauthtype ==
1641 Ndis802_11AuthModeOpen)
1642 erq->flags |= IW_ENCODE_OPEN;
1643 else if (padapter->securitypriv.ndisauthtype ==
1644 Ndis802_11AuthModeShared)
1645 erq->flags |= IW_ENCODE_RESTRICTED;
1646 } else {
1647 erq->length = 0;
1648 erq->flags |= IW_ENCODE_DISABLED;
1649 }
1650 break;
1651 case Ndis802_11Encryption2Enabled:
1652 case Ndis802_11Encryption3Enabled:
1653 erq->length = 16;
1654 erq->flags |= (IW_ENCODE_ENABLED | IW_ENCODE_OPEN |
1655 IW_ENCODE_NOKEY);
1656 break;
1657 default:
1658 erq->length = 0;
1659 erq->flags |= IW_ENCODE_DISABLED;
1660 break;
1661 }
1662 return ret;
1663}
1664
1665static int r8711_wx_get_power(struct net_device *dev,
1666 struct iw_request_info *info,
1667 union iwreq_data *wrqu, char *extra)
1668{
1669 wrqu->power.value = 0;
1670 wrqu->power.fixed = 0; /* no auto select */
1671 wrqu->power.disabled = 1;
1672 return 0;
1673}
1674
1675static int r871x_wx_set_gen_ie(struct net_device *dev,
1676 struct iw_request_info *info,
1677 union iwreq_data *wrqu, char *extra)
1678{
Julia Lawall8f47c282015-03-29 14:54:12 +02001679 struct _adapter *padapter = netdev_priv(dev);
Larry Finger2865d422010-08-20 10:15:30 -05001680
1681 return r871x_set_wpa_ie(padapter, extra, wrqu->data.length);
1682}
1683
1684static int r871x_wx_set_auth(struct net_device *dev,
1685 struct iw_request_info *info,
1686 union iwreq_data *wrqu, char *extra)
1687{
Julia Lawall8f47c282015-03-29 14:54:12 +02001688 struct _adapter *padapter = netdev_priv(dev);
Larry Finger2865d422010-08-20 10:15:30 -05001689 struct iw_param *param = (struct iw_param *)&(wrqu->param);
1690 int paramid;
1691 int paramval;
1692 int ret = 0;
1693
1694 paramid = param->flags & IW_AUTH_INDEX;
1695 paramval = param->value;
1696 switch (paramid) {
1697 case IW_AUTH_WPA_VERSION:
1698 break;
1699 case IW_AUTH_CIPHER_PAIRWISE:
1700 break;
1701 case IW_AUTH_CIPHER_GROUP:
1702 break;
1703 case IW_AUTH_KEY_MGMT:
1704 /*
1705 * ??? does not use these parameters
1706 */
1707 break;
1708 case IW_AUTH_TKIP_COUNTERMEASURES:
1709 if (paramval) {
1710 /* wpa_supplicant is enabling tkip countermeasure. */
1711 padapter->securitypriv.btkip_countermeasure = true;
1712 } else {
1713 /* wpa_supplicant is disabling tkip countermeasure. */
1714 padapter->securitypriv.btkip_countermeasure = false;
1715 }
1716 break;
1717 case IW_AUTH_DROP_UNENCRYPTED:
1718 /* HACK:
1719 *
1720 * wpa_supplicant calls set_wpa_enabled when the driver
1721 * is loaded and unloaded, regardless of if WPA is being
1722 * used. No other calls are made which can be used to
1723 * determine if encryption will be used or not prior to
1724 * association being expected. If encryption is not being
1725 * used, drop_unencrypted is set to false, else true -- we
1726 * can use this to determine if the CAP_PRIVACY_ON bit should
1727 * be set.
1728 */
1729 if (padapter->securitypriv.ndisencryptstatus ==
1730 Ndis802_11Encryption1Enabled) {
1731 /* it means init value, or using wep,
1732 * ndisencryptstatus =
1733 * Ndis802_11Encryption1Enabled,
1734 * then it needn't reset it;
1735 */
1736 break;
1737 }
1738
1739 if (paramval) {
1740 padapter->securitypriv.ndisencryptstatus =
1741 Ndis802_11EncryptionDisabled;
1742 padapter->securitypriv.PrivacyAlgrthm =
1743 _NO_PRIVACY_;
1744 padapter->securitypriv.XGrpPrivacy =
1745 _NO_PRIVACY_;
1746 padapter->securitypriv.AuthAlgrthm = 0;
1747 padapter->securitypriv.ndisauthtype =
1748 Ndis802_11AuthModeOpen;
1749 }
1750 break;
1751 case IW_AUTH_80211_AUTH_ALG:
1752 ret = wpa_set_auth_algs(dev, (u32)paramval);
1753 break;
1754 case IW_AUTH_WPA_ENABLED:
1755 break;
1756 case IW_AUTH_RX_UNENCRYPTED_EAPOL:
1757 break;
1758 case IW_AUTH_PRIVACY_INVOKED:
1759 break;
1760 default:
1761 return -EOPNOTSUPP;
1762 }
1763
1764 return ret;
1765}
1766
1767static int r871x_wx_set_enc_ext(struct net_device *dev,
1768 struct iw_request_info *info,
1769 union iwreq_data *wrqu, char *extra)
1770{
1771 struct iw_point *pencoding = &wrqu->encoding;
1772 struct iw_encode_ext *pext = (struct iw_encode_ext *)extra;
1773 struct ieee_param *param = NULL;
1774 char *alg_name;
1775 u32 param_len;
1776 int ret = 0;
1777
Larry Finger2865d422010-08-20 10:15:30 -05001778 switch (pext->alg) {
1779 case IW_ENCODE_ALG_NONE:
1780 alg_name = "none";
1781 break;
1782 case IW_ENCODE_ALG_WEP:
1783 alg_name = "WEP";
1784 break;
1785 case IW_ENCODE_ALG_TKIP:
1786 alg_name = "TKIP";
1787 break;
1788 case IW_ENCODE_ALG_CCMP:
1789 alg_name = "CCMP";
1790 break;
1791 default:
Ali Bahar2192e602011-09-04 03:14:24 +08001792 return -EINVAL;
Larry Finger2865d422010-08-20 10:15:30 -05001793 }
Christian Engelmayer55d4f6c2014-05-07 21:36:48 +02001794
1795 param_len = sizeof(struct ieee_param) + pext->key_len;
Vitaly Osipov91d435f2014-05-24 18:19:27 +10001796 param = kzalloc(param_len, GFP_ATOMIC);
Christian Engelmayer55d4f6c2014-05-07 21:36:48 +02001797 if (param == NULL)
1798 return -ENOMEM;
Christian Engelmayer55d4f6c2014-05-07 21:36:48 +02001799 param->cmd = IEEE_CMD_SET_ENCRYPTION;
Punit Varae904cc82015-10-14 23:55:52 +05301800 eth_broadcast_addr(param->sta_addr);
Larry Finger2865d422010-08-20 10:15:30 -05001801 strncpy((char *)param->u.crypt.alg, alg_name, IEEE_CRYPT_ALG_NAME_LEN);
1802 if (pext->ext_flags & IW_ENCODE_EXT_GROUP_KEY)
1803 param->u.crypt.set_tx = 0;
1804 if (pext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)
1805 param->u.crypt.set_tx = 1;
1806 param->u.crypt.idx = (pencoding->flags & 0x00FF) - 1;
1807 if (pext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID)
1808 memcpy(param->u.crypt.seq, pext->rx_seq, 8);
1809 if (pext->key_len) {
1810 param->u.crypt.key_len = pext->key_len;
1811 memcpy(param + 1, pext + 1, pext->key_len);
1812 }
1813 ret = wpa_set_encryption(dev, param, param_len);
Alexander Beregalov40083862011-03-26 20:18:14 +03001814 kfree(param);
Larry Finger2865d422010-08-20 10:15:30 -05001815 return ret;
1816}
1817
1818static int r871x_wx_get_nick(struct net_device *dev,
1819 struct iw_request_info *info,
1820 union iwreq_data *wrqu, char *extra)
1821{
1822 if (extra) {
1823 wrqu->data.length = 8;
1824 wrqu->data.flags = 1;
1825 memcpy(extra, "rtl_wifi", 8);
1826 }
1827 return 0;
1828}
1829
1830static int r8711_wx_read32(struct net_device *dev,
1831 struct iw_request_info *info,
1832 union iwreq_data *wrqu, char *keybuf)
1833{
Julia Lawall8f47c282015-03-29 14:54:12 +02001834 struct _adapter *padapter = netdev_priv(dev);
Larry Finger2865d422010-08-20 10:15:30 -05001835 u32 addr;
1836 u32 data32;
1837
1838 get_user(addr, (u32 __user *)wrqu->data.pointer);
1839 data32 = r8712_read32(padapter, addr);
1840 put_user(data32, (u32 __user *)wrqu->data.pointer);
1841 wrqu->data.length = (data32 & 0xffff0000) >> 16;
1842 wrqu->data.flags = data32 & 0xffff;
1843 get_user(addr, (u32 __user *)wrqu->data.pointer);
1844 return 0;
1845}
1846
1847static int r8711_wx_write32(struct net_device *dev,
1848 struct iw_request_info *info,
1849 union iwreq_data *wrqu, char *keybuf)
1850{
Julia Lawall8f47c282015-03-29 14:54:12 +02001851 struct _adapter *padapter = netdev_priv(dev);
Larry Finger2865d422010-08-20 10:15:30 -05001852 u32 addr;
1853 u32 data32;
1854
1855 get_user(addr, (u32 __user *)wrqu->data.pointer);
Thomas Cort77e73e82013-10-01 11:26:55 -04001856 data32 = ((u32)wrqu->data.length<<16) | (u32)wrqu->data.flags;
Larry Finger2865d422010-08-20 10:15:30 -05001857 r8712_write32(padapter, addr, data32);
1858 return 0;
1859}
1860
1861static int dummy(struct net_device *dev,
1862 struct iw_request_info *a,
1863 union iwreq_data *wrqu, char *b)
1864{
Ali Bahar2192e602011-09-04 03:14:24 +08001865 return -ENOSYS;
Larry Finger2865d422010-08-20 10:15:30 -05001866}
1867
1868static int r8711_drvext_hdl(struct net_device *dev,
1869 struct iw_request_info *info,
1870 union iwreq_data *wrqu, char *extra)
1871{
1872 return 0;
1873}
1874
1875static int r871x_mp_ioctl_hdl(struct net_device *dev,
1876 struct iw_request_info *info,
1877 union iwreq_data *wrqu, char *extra)
1878{
Julia Lawall8f47c282015-03-29 14:54:12 +02001879 struct _adapter *padapter = netdev_priv(dev);
Larry Finger2865d422010-08-20 10:15:30 -05001880 struct iw_point *p = &wrqu->data;
1881 struct oid_par_priv oid_par;
1882 struct mp_ioctl_handler *phandler;
1883 struct mp_ioctl_param *poidparam;
1884 unsigned long BytesRead, BytesWritten, BytesNeeded;
Dan Carpenterb5eed732015-04-08 14:19:00 +03001885 u8 *pparmbuf, bset;
Larry Finger2865d422010-08-20 10:15:30 -05001886 u16 len;
1887 uint status;
1888 int ret = 0;
1889
Dan Carpenterb5eed732015-04-08 14:19:00 +03001890 if ((!p->length) || (!p->pointer))
1891 return -EINVAL;
1892
Larry Finger2865d422010-08-20 10:15:30 -05001893 bset = (u8)(p->flags & 0xFFFF);
1894 len = p->length;
Cristina Opriceana45de4322015-03-28 02:57:34 +02001895 pparmbuf = memdup_user(p->pointer, len);
Dan Carpenterb5eed732015-04-08 14:19:00 +03001896 if (IS_ERR(pparmbuf))
1897 return PTR_ERR(pparmbuf);
1898
Larry Finger2865d422010-08-20 10:15:30 -05001899 poidparam = (struct mp_ioctl_param *)pparmbuf;
1900 if (poidparam->subcode >= MAX_MP_IOCTL_SUBCODE) {
1901 ret = -EINVAL;
1902 goto _r871x_mp_ioctl_hdl_exit;
1903 }
1904 phandler = mp_ioctl_hdl + poidparam->subcode;
1905 if ((phandler->paramsize != 0) &&
1906 (poidparam->len < phandler->paramsize)) {
1907 ret = -EINVAL;
1908 goto _r871x_mp_ioctl_hdl_exit;
1909 }
Luis de Bethencourt168a2c12015-10-19 18:15:29 +01001910 if (phandler->oid == 0 && phandler->handler) {
Larry Finger2865d422010-08-20 10:15:30 -05001911 status = phandler->handler(&oid_par);
Luis de Bethencourt168a2c12015-10-19 18:15:29 +01001912 } else if (phandler->handler) {
Larry Finger2865d422010-08-20 10:15:30 -05001913 oid_par.adapter_context = padapter;
1914 oid_par.oid = phandler->oid;
1915 oid_par.information_buf = poidparam->data;
1916 oid_par.information_buf_len = poidparam->len;
1917 oid_par.dbg = 0;
1918 BytesWritten = 0;
1919 BytesNeeded = 0;
1920 if (bset) {
1921 oid_par.bytes_rw = &BytesRead;
1922 oid_par.bytes_needed = &BytesNeeded;
1923 oid_par.type_of_oid = SET_OID;
1924 } else {
1925 oid_par.bytes_rw = &BytesWritten;
1926 oid_par.bytes_needed = &BytesNeeded;
1927 oid_par.type_of_oid = QUERY_OID;
1928 }
1929 status = phandler->handler(&oid_par);
1930 /* todo:check status, BytesNeeded, etc. */
1931 } else {
Przemo Firszt87a573a2012-12-10 23:21:21 +00001932 netdev_info(dev, "r8712u: %s: err!, subcode=%d, oid=%d, handler=%p\n",
1933 __func__, poidparam->subcode, phandler->oid,
1934 phandler->handler);
Larry Finger2865d422010-08-20 10:15:30 -05001935 ret = -EFAULT;
1936 goto _r871x_mp_ioctl_hdl_exit;
1937 }
1938 if (bset == 0x00) { /* query info */
1939 if (copy_to_user(p->pointer, pparmbuf, len))
1940 ret = -EFAULT;
1941 }
1942 if (status) {
1943 ret = -EFAULT;
1944 goto _r871x_mp_ioctl_hdl_exit;
1945 }
1946_r871x_mp_ioctl_hdl_exit:
Ilia Mirkinb7977fa2011-03-13 00:29:08 -05001947 kfree(pparmbuf);
Larry Finger2865d422010-08-20 10:15:30 -05001948 return ret;
1949}
1950
1951static int r871x_get_ap_info(struct net_device *dev,
1952 struct iw_request_info *info,
1953 union iwreq_data *wrqu, char *extra)
1954{
Julia Lawall8f47c282015-03-29 14:54:12 +02001955 struct _adapter *padapter = netdev_priv(dev);
Larry Finger2865d422010-08-20 10:15:30 -05001956 struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
1957 struct __queue *queue = &pmlmepriv->scanned_queue;
1958 struct iw_point *pdata = &wrqu->data;
1959 struct wlan_network *pnetwork = NULL;
1960 u32 cnt = 0, wpa_ielen;
1961 unsigned long irqL;
1962 struct list_head *plist, *phead;
1963 unsigned char *pbuf;
1964 u8 bssid[ETH_ALEN];
1965 char data[32];
1966
1967 if (padapter->bDriverStopped || (pdata == NULL))
1968 return -EINVAL;
1969 while (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY|_FW_UNDER_LINKING)) {
1970 msleep(30);
1971 cnt++;
1972 if (cnt > 100)
1973 break;
1974 }
1975 pdata->flags = 0;
1976 if (pdata->length >= 32) {
1977 if (copy_from_user(data, pdata->pointer, 32))
1978 return -EINVAL;
Luis de Bethencourt168a2c12015-10-19 18:15:29 +01001979 } else {
Larry Finger2865d422010-08-20 10:15:30 -05001980 return -EINVAL;
Luis de Bethencourt168a2c12015-10-19 18:15:29 +01001981 }
Larry Finger2865d422010-08-20 10:15:30 -05001982 spin_lock_irqsave(&(pmlmepriv->scanned_queue.lock), irqL);
James A Shackleforde99a4282014-06-24 22:52:39 -04001983 phead = &queue->queue;
James A Shackleford849fb0a2014-06-24 22:52:38 -04001984 plist = phead->next;
Larry Finger2865d422010-08-20 10:15:30 -05001985 while (1) {
Luis de Bethencourt1ca96882015-10-19 18:14:29 +01001986 if (end_of_queue_search(phead, plist))
Larry Finger2865d422010-08-20 10:15:30 -05001987 break;
1988 pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
Andy Shevchenko3fe1be82015-10-01 16:18:07 +03001989 if (!mac_pton(data, bssid)) {
Przemo Firszt87a573a2012-12-10 23:21:21 +00001990 netdev_info(dev, "r8712u: Invalid BSSID '%s'.\n",
1991 (u8 *)data);
Larry Finger2865d422010-08-20 10:15:30 -05001992 spin_unlock_irqrestore(&(pmlmepriv->scanned_queue.lock),
Przemo Firszt87a573a2012-12-10 23:21:21 +00001993 irqL);
Larry Finger2865d422010-08-20 10:15:30 -05001994 return -EINVAL;
1995 }
Przemo Firszt87a573a2012-12-10 23:21:21 +00001996 netdev_info(dev, "r8712u: BSSID:%pM\n", bssid);
Punit Varaa1b42be2015-10-14 23:55:53 +05301997 if (ether_addr_equal(bssid, pnetwork->network.MacAddress)) {
Larry Finger2865d422010-08-20 10:15:30 -05001998 /* BSSID match, then check if supporting wpa/wpa2 */
1999 pbuf = r8712_get_wpa_ie(&pnetwork->network.IEs[12],
2000 &wpa_ielen, pnetwork->network.IELength-12);
2001 if (pbuf && (wpa_ielen > 0)) {
2002 pdata->flags = 1;
2003 break;
2004 }
2005 pbuf = r8712_get_wpa2_ie(&pnetwork->network.IEs[12],
2006 &wpa_ielen, pnetwork->network.IELength-12);
2007 if (pbuf && (wpa_ielen > 0)) {
2008 pdata->flags = 2;
2009 break;
2010 }
2011 }
James A Shackleford849fb0a2014-06-24 22:52:38 -04002012 plist = plist->next;
Larry Finger2865d422010-08-20 10:15:30 -05002013 }
2014 spin_unlock_irqrestore(&(pmlmepriv->scanned_queue.lock), irqL);
2015 if (pdata->length >= 34) {
2016 if (copy_to_user((u8 __user *)pdata->pointer + 32,
2017 (u8 *)&pdata->flags, 1))
2018 return -EINVAL;
2019 }
2020 return 0;
2021}
2022
2023static int r871x_set_pid(struct net_device *dev,
2024 struct iw_request_info *info,
2025 union iwreq_data *wrqu, char *extra)
2026{
Julia Lawall8f47c282015-03-29 14:54:12 +02002027 struct _adapter *padapter = netdev_priv(dev);
Larry Finger2865d422010-08-20 10:15:30 -05002028 struct iw_point *pdata = &wrqu->data;
2029
2030 if ((padapter->bDriverStopped) || (pdata == NULL))
2031 return -EINVAL;
2032 if (copy_from_user(&padapter->pid, pdata->pointer, sizeof(int)))
2033 return -EINVAL;
2034 return 0;
2035}
2036
Ali Baharc6dc0012011-09-04 03:14:20 +08002037static int r871x_set_chplan(struct net_device *dev,
2038 struct iw_request_info *info,
2039 union iwreq_data *wrqu, char *extra)
2040{
2041 int ret = 0;
Julia Lawall8f47c282015-03-29 14:54:12 +02002042 struct _adapter *padapter = netdev_priv(dev);
Ali Baharc6dc0012011-09-04 03:14:20 +08002043 struct iw_point *pdata = &wrqu->data;
2044 int ch_plan = -1;
2045
2046 if ((padapter->bDriverStopped) || (pdata == NULL)) {
2047 ret = -EINVAL;
2048 goto exit;
2049 }
2050 ch_plan = (int)*extra;
2051 r8712_set_chplan_cmd(padapter, ch_plan);
2052
2053exit:
2054
2055 return ret;
2056}
2057
Larry Finger2865d422010-08-20 10:15:30 -05002058static int r871x_wps_start(struct net_device *dev,
2059 struct iw_request_info *info,
2060 union iwreq_data *wrqu, char *extra)
2061{
Julia Lawall8f47c282015-03-29 14:54:12 +02002062 struct _adapter *padapter = netdev_priv(dev);
Larry Finger2865d422010-08-20 10:15:30 -05002063 struct iw_point *pdata = &wrqu->data;
2064 u32 u32wps_start = 0;
Larry Finger2865d422010-08-20 10:15:30 -05002065
Larry Finger2865d422010-08-20 10:15:30 -05002066 if ((padapter->bDriverStopped) || (pdata == NULL))
2067 return -EINVAL;
Wei Yongjun605fba82012-10-08 08:43:45 +08002068 if (copy_from_user((void *)&u32wps_start, pdata->pointer, 4))
2069 return -EFAULT;
Larry Finger2865d422010-08-20 10:15:30 -05002070 if (u32wps_start == 0)
2071 u32wps_start = *extra;
2072 if (u32wps_start == 1) /* WPS Start */
2073 padapter->ledpriv.LedControlHandler(padapter,
2074 LED_CTL_START_WPS);
2075 else if (u32wps_start == 2) /* WPS Stop because of wps success */
2076 padapter->ledpriv.LedControlHandler(padapter,
2077 LED_CTL_STOP_WPS);
2078 else if (u32wps_start == 3) /* WPS Stop because of wps fail */
2079 padapter->ledpriv.LedControlHandler(padapter,
2080 LED_CTL_STOP_WPS_FAIL);
2081 return 0;
2082}
2083
2084static int wpa_set_param(struct net_device *dev, u8 name, u32 value)
2085{
Julia Lawall8f47c282015-03-29 14:54:12 +02002086 struct _adapter *padapter = netdev_priv(dev);
Larry Finger2865d422010-08-20 10:15:30 -05002087
2088 switch (name) {
2089 case IEEE_PARAM_WPA_ENABLED:
2090 padapter->securitypriv.AuthAlgrthm = 2; /* 802.1x */
2091 switch ((value)&0xff) {
2092 case 1: /* WPA */
2093 padapter->securitypriv.ndisauthtype =
2094 Ndis802_11AuthModeWPAPSK; /* WPA_PSK */
2095 padapter->securitypriv.ndisencryptstatus =
2096 Ndis802_11Encryption2Enabled;
2097 break;
2098 case 2: /* WPA2 */
2099 padapter->securitypriv.ndisauthtype =
2100 Ndis802_11AuthModeWPA2PSK; /* WPA2_PSK */
2101 padapter->securitypriv.ndisencryptstatus =
2102 Ndis802_11Encryption3Enabled;
2103 break;
2104 }
2105 break;
2106 case IEEE_PARAM_TKIP_COUNTERMEASURES:
2107 break;
2108 case IEEE_PARAM_DROP_UNENCRYPTED:
2109 /* HACK:
2110 *
2111 * wpa_supplicant calls set_wpa_enabled when the driver
2112 * is loaded and unloaded, regardless of if WPA is being
2113 * used. No other calls are made which can be used to
2114 * determine if encryption will be used or not prior to
2115 * association being expected. If encryption is not being
2116 * used, drop_unencrypted is set to false, else true -- we
2117 * can use this to determine if the CAP_PRIVACY_ON bit should
2118 * be set.
2119 */
2120 break;
2121 case IEEE_PARAM_PRIVACY_INVOKED:
2122 break;
2123 case IEEE_PARAM_AUTH_ALGS:
2124 return wpa_set_auth_algs(dev, value);
Larry Finger2865d422010-08-20 10:15:30 -05002125 case IEEE_PARAM_IEEE_802_1X:
2126 break;
2127 case IEEE_PARAM_WPAX_SELECT:
2128 /* added for WPA2 mixed mode */
2129 break;
2130 default:
2131 return -EOPNOTSUPP;
2132 }
2133 return 0;
2134}
2135
2136static int wpa_mlme(struct net_device *dev, u32 command, u32 reason)
2137{
Julia Lawall8f47c282015-03-29 14:54:12 +02002138 struct _adapter *padapter = netdev_priv(dev);
Larry Finger2865d422010-08-20 10:15:30 -05002139
2140 switch (command) {
2141 case IEEE_MLME_STA_DEAUTH:
2142 if (!r8712_set_802_11_disassociate(padapter))
2143 return -1;
2144 break;
2145 case IEEE_MLME_STA_DISASSOC:
2146 if (!r8712_set_802_11_disassociate(padapter))
2147 return -1;
2148 break;
2149 default:
2150 return -EOPNOTSUPP;
2151 }
2152 return 0;
2153}
2154
2155static int wpa_supplicant_ioctl(struct net_device *dev, struct iw_point *p)
2156{
2157 struct ieee_param *param;
2158 int ret = 0;
Julia Lawall8f47c282015-03-29 14:54:12 +02002159 struct _adapter *padapter = netdev_priv(dev);
Larry Finger2865d422010-08-20 10:15:30 -05002160
2161 if (p->length < sizeof(struct ieee_param) || !p->pointer)
2162 return -EINVAL;
Vitaly Osipov91d435f2014-05-24 18:19:27 +10002163 param = memdup_user(p->pointer, p->length);
2164 if (IS_ERR(param))
2165 return PTR_ERR(param);
Larry Finger2865d422010-08-20 10:15:30 -05002166 switch (param->cmd) {
2167 case IEEE_CMD_SET_WPA_PARAM:
2168 ret = wpa_set_param(dev, param->u.wpa_param.name,
2169 param->u.wpa_param.value);
2170 break;
2171 case IEEE_CMD_SET_WPA_IE:
2172 ret = r871x_set_wpa_ie(padapter, (char *)param->u.wpa_ie.data,
2173 (u16)param->u.wpa_ie.len);
2174 break;
2175 case IEEE_CMD_SET_ENCRYPTION:
2176 ret = wpa_set_encryption(dev, param, p->length);
2177 break;
2178 case IEEE_CMD_MLME:
2179 ret = wpa_mlme(dev, param->u.mlme.command,
2180 param->u.mlme.reason_code);
2181 break;
2182 default:
2183 ret = -EOPNOTSUPP;
2184 break;
2185 }
2186 if (ret == 0 && copy_to_user(p->pointer, param, p->length))
2187 ret = -EFAULT;
Tapasweni Pathak646da832014-10-08 20:41:26 +05302188 kfree(param);
Larry Finger2865d422010-08-20 10:15:30 -05002189 return ret;
2190}
2191
2192/* based on "driver_ipw" and for hostapd */
2193int r871x_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
2194{
2195 struct iwreq *wrq = (struct iwreq *)rq;
2196
2197 switch (cmd) {
2198 case RTL_IOCTL_WPA_SUPPLICANT:
2199 return wpa_supplicant_ioctl(dev, &wrq->u.data);
2200 default:
2201 return -EOPNOTSUPP;
2202 }
2203 return 0;
2204}
2205
2206static iw_handler r8711_handlers[] = {
2207 NULL, /* SIOCSIWCOMMIT */
2208 r8711_wx_get_name, /* SIOCGIWNAME */
2209 dummy, /* SIOCSIWNWID */
2210 dummy, /* SIOCGIWNWID */
2211 r8711_wx_set_freq, /* SIOCSIWFREQ */
2212 r8711_wx_get_freq, /* SIOCGIWFREQ */
2213 r8711_wx_set_mode, /* SIOCSIWMODE */
2214 r8711_wx_get_mode, /* SIOCGIWMODE */
2215 dummy, /* SIOCSIWSENS */
2216 r8711_wx_get_sens, /* SIOCGIWSENS */
2217 NULL, /* SIOCSIWRANGE */
2218 r8711_wx_get_range, /* SIOCGIWRANGE */
2219 r871x_wx_set_priv, /* SIOCSIWPRIV */
2220 NULL, /* SIOCGIWPRIV */
2221 NULL, /* SIOCSIWSTATS */
2222 NULL, /* SIOCGIWSTATS */
2223 dummy, /* SIOCSIWSPY */
2224 dummy, /* SIOCGIWSPY */
2225 NULL, /* SIOCGIWTHRSPY */
2226 NULL, /* SIOCWIWTHRSPY */
2227 r8711_wx_set_wap, /* SIOCSIWAP */
2228 r8711_wx_get_wap, /* SIOCGIWAP */
2229 r871x_wx_set_mlme, /* request MLME operation;
Punit Varad32c16d2015-10-14 23:55:54 +05302230 * uses struct iw_mlme
2231 */
Larry Finger2865d422010-08-20 10:15:30 -05002232 dummy, /* SIOCGIWAPLIST -- deprecated */
2233 r8711_wx_set_scan, /* SIOCSIWSCAN */
2234 r8711_wx_get_scan, /* SIOCGIWSCAN */
2235 r8711_wx_set_essid, /* SIOCSIWESSID */
2236 r8711_wx_get_essid, /* SIOCGIWESSID */
2237 dummy, /* SIOCSIWNICKN */
2238 r871x_wx_get_nick, /* SIOCGIWNICKN */
2239 NULL, /* -- hole -- */
2240 NULL, /* -- hole -- */
2241 r8711_wx_set_rate, /* SIOCSIWRATE */
2242 r8711_wx_get_rate, /* SIOCGIWRATE */
2243 dummy, /* SIOCSIWRTS */
2244 r8711_wx_get_rts, /* SIOCGIWRTS */
2245 r8711_wx_set_frag, /* SIOCSIWFRAG */
2246 r8711_wx_get_frag, /* SIOCGIWFRAG */
2247 dummy, /* SIOCSIWTXPOW */
2248 dummy, /* SIOCGIWTXPOW */
2249 dummy, /* SIOCSIWRETRY */
2250 r8711_wx_get_retry, /* SIOCGIWRETRY */
2251 r8711_wx_set_enc, /* SIOCSIWENCODE */
2252 r8711_wx_get_enc, /* SIOCGIWENCODE */
2253 dummy, /* SIOCSIWPOWER */
2254 r8711_wx_get_power, /* SIOCGIWPOWER */
2255 NULL, /*---hole---*/
2256 NULL, /*---hole---*/
2257 r871x_wx_set_gen_ie, /* SIOCSIWGENIE */
2258 NULL, /* SIOCGIWGENIE */
2259 r871x_wx_set_auth, /* SIOCSIWAUTH */
2260 NULL, /* SIOCGIWAUTH */
2261 r871x_wx_set_enc_ext, /* SIOCSIWENCODEEXT */
2262 NULL, /* SIOCGIWENCODEEXT */
2263 r871x_wx_set_pmkid, /* SIOCSIWPMKSA */
2264 NULL, /*---hole---*/
2265};
2266
2267static const struct iw_priv_args r8711_private_args[] = {
2268 {
2269 SIOCIWFIRSTPRIV + 0x0,
2270 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "read32"
2271 },
2272 {
2273 SIOCIWFIRSTPRIV + 0x1,
2274 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "write32"
2275 },
2276 {
2277 SIOCIWFIRSTPRIV + 0x2, 0, 0, "driver_ext"
2278 },
2279 {
2280 SIOCIWFIRSTPRIV + 0x3, 0, 0, "mp_ioctl"
2281 },
2282 {
2283 SIOCIWFIRSTPRIV + 0x4,
2284 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "apinfo"
2285 },
2286 {
2287 SIOCIWFIRSTPRIV + 0x5,
2288 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "setpid"
2289 },
2290 {
2291 SIOCIWFIRSTPRIV + 0x6,
2292 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "wps_start"
Ali Baharc6dc0012011-09-04 03:14:20 +08002293 },
2294 {
2295 SIOCIWFIRSTPRIV + 0x7,
2296 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "chplan"
Larry Finger2865d422010-08-20 10:15:30 -05002297 }
2298};
2299
2300static iw_handler r8711_private_handler[] = {
2301 r8711_wx_read32,
2302 r8711_wx_write32,
2303 r8711_drvext_hdl,
2304 r871x_mp_ioctl_hdl,
2305 r871x_get_ap_info, /*for MM DTV platform*/
2306 r871x_set_pid,
Ali Baharc6dc0012011-09-04 03:14:20 +08002307 r871x_wps_start,
2308 r871x_set_chplan
Larry Finger2865d422010-08-20 10:15:30 -05002309};
2310
2311static struct iw_statistics *r871x_get_wireless_stats(struct net_device *dev)
2312{
Julia Lawall8f47c282015-03-29 14:54:12 +02002313 struct _adapter *padapter = netdev_priv(dev);
Larry Finger2865d422010-08-20 10:15:30 -05002314 struct iw_statistics *piwstats = &padapter->iwstats;
2315 int tmp_level = 0;
2316 int tmp_qual = 0;
2317 int tmp_noise = 0;
2318
2319 if (check_fwstate(&padapter->mlmepriv, _FW_LINKED) != true) {
2320 piwstats->qual.qual = 0;
2321 piwstats->qual.level = 0;
2322 piwstats->qual.noise = 0;
2323 } else {
2324 /* show percentage, we need transfer dbm to orignal value. */
2325 tmp_level = padapter->recvpriv.fw_rssi;
2326 tmp_qual = padapter->recvpriv.signal;
2327 tmp_noise = padapter->recvpriv.noise;
2328 piwstats->qual.level = tmp_level;
Larry Fingerda3e6ec2012-02-26 22:08:36 -06002329 piwstats->qual.qual = tmp_qual;
Larry Finger2865d422010-08-20 10:15:30 -05002330 piwstats->qual.noise = tmp_noise;
2331 }
2332 piwstats->qual.updated = IW_QUAL_ALL_UPDATED;
2333 return &padapter->iwstats;
2334}
2335
2336struct iw_handler_def r871x_handlers_def = {
2337 .standard = r8711_handlers,
Jim Cromieb330f602012-04-10 16:06:41 -06002338 .num_standard = ARRAY_SIZE(r8711_handlers),
Larry Finger2865d422010-08-20 10:15:30 -05002339 .private = r8711_private_handler,
2340 .private_args = (struct iw_priv_args *)r8711_private_args,
Jim Cromieb330f602012-04-10 16:06:41 -06002341 .num_private = ARRAY_SIZE(r8711_private_handler),
Larry Finger2865d422010-08-20 10:15:30 -05002342 .num_private_args = sizeof(r8711_private_args) /
2343 sizeof(struct iw_priv_args),
Ali Baharc6dc0012011-09-04 03:14:20 +08002344 .get_wireless_stats = r871x_get_wireless_stats
Larry Finger2865d422010-08-20 10:15:30 -05002345};