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