blob: b1500ee9a5cf8f97a2345324429fb119064116de [file] [log] [blame]
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -07001/******************************************************************************
2
3 Copyright(c) 2004 Intel Corporation. All rights reserved.
4
5 Portions of this file are based on the WEP enablement code provided by the
6 Host AP project hostap-drivers v0.1.3
7 Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
8 <jkmaline@cc.hut.fi>
9 Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
10
11 This program is free software; you can redistribute it and/or modify it
12 under the terms of version 2 of the GNU General Public License as
13 published by the Free Software Foundation.
14
15 This program is distributed in the hope that it will be useful, but WITHOUT
16 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
18 more details.
19
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -070020 The full GNU General Public License is included in this distribution in the
21 file called LICENSE.
22
23 Contact Information:
24 James P. Ketrenos <ipw2100-admin@linux.intel.com>
25 Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
26
27******************************************************************************/
28#include <linux/wireless.h>
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -070029#include <linux/kmod.h>
30#include <linux/module.h>
Ksenija Stanojevicc63eee52015-02-28 19:46:57 +010031#include <linux/etherdevice.h>
Larry Finger94a79942011-08-23 19:00:42 -050032#include "rtllib.h"
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -070033struct modes_unit {
34 char *mode_string;
35 int mode_size;
36};
Larry Finger94a79942011-08-23 19:00:42 -050037static struct modes_unit rtllib_modes[] = {
Larry Finger62f27cc2011-08-25 11:48:29 -050038 {"a", 1},
39 {"b", 1},
40 {"g", 1},
41 {"?", 1},
42 {"N-24G", 5},
43 {"N-5G", 4},
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -070044};
45
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -070046#define MAX_CUSTOM_LEN 64
Larry Finger94a79942011-08-23 19:00:42 -050047static inline char *rtl819x_translate_scan(struct rtllib_device *ieee,
48 char *start, char *stop,
49 struct rtllib_network *network,
Larry Finger62f27cc2011-08-25 11:48:29 -050050 struct iw_request_info *info)
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -070051{
52 char custom[MAX_CUSTOM_LEN];
53 char proto_name[IFNAMSIZ];
54 char *pname = proto_name;
55 char *p;
56 struct iw_event iwe;
57 int i, j;
58 u16 max_rate, rate;
59 static u8 EWC11NHTCap[] = {0x00, 0x90, 0x4c, 0x33};
60
61 /* First entry *MUST* be the AP MAC address */
62 iwe.cmd = SIOCGIWAP;
63 iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
Ksenija Stanojevicc63eee52015-02-28 19:46:57 +010064 ether_addr_copy(iwe.u.ap_addr.sa_data, network->bssid);
Larry Finger62f27cc2011-08-25 11:48:29 -050065 start = iwe_stream_add_event_rsl(info, start, stop,
66 &iwe, IW_EV_ADDR_LEN);
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -070067 /* Remaining entries will be displayed in the order we provide them */
68
69 /* Add the ESSID */
70 iwe.cmd = SIOCGIWESSID;
71 iwe.u.data.flags = 1;
Larry Finger62f27cc2011-08-25 11:48:29 -050072 if (network->ssid_len > 0) {
Darshana Padmadasd009f0d2015-03-08 23:33:40 +053073 iwe.u.data.length = min_t(u8, network->ssid_len, 32);
Larry Finger62f27cc2011-08-25 11:48:29 -050074 start = iwe_stream_add_point_rsl(info, start, stop, &iwe,
75 network->ssid);
76 } else if (network->hidden_ssid_len == 0) {
Larry Finger94a79942011-08-23 19:00:42 -050077 iwe.u.data.length = sizeof("<hidden>");
Larry Finger62f27cc2011-08-25 11:48:29 -050078 start = iwe_stream_add_point_rsl(info, start, stop,
79 &iwe, "<hidden>");
80 } else {
Darshana Padmadasd009f0d2015-03-08 23:33:40 +053081 iwe.u.data.length = min_t(u8, network->hidden_ssid_len, 32);
Larry Finger62f27cc2011-08-25 11:48:29 -050082 start = iwe_stream_add_point_rsl(info, start, stop, &iwe,
83 network->hidden_ssid);
Larry Finger94a79942011-08-23 19:00:42 -050084 }
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -070085 /* Add the protocol name */
86 iwe.cmd = SIOCGIWNAME;
Jim Cromieb330f602012-04-10 16:06:41 -060087 for (i = 0; i < ARRAY_SIZE(rtllib_modes); i++) {
Larry Finger94a79942011-08-23 19:00:42 -050088 if (network->mode&(1<<i)) {
Larry Finger62f27cc2011-08-25 11:48:29 -050089 sprintf(pname, rtllib_modes[i].mode_string,
90 rtllib_modes[i].mode_size);
91 pname += rtllib_modes[i].mode_size;
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -070092 }
93 }
94 *pname = '\0';
95 snprintf(iwe.u.name, IFNAMSIZ, "IEEE802.11%s", proto_name);
Larry Finger62f27cc2011-08-25 11:48:29 -050096 start = iwe_stream_add_event_rsl(info, start, stop,
97 &iwe, IW_EV_CHAR_LEN);
98 /* Add mode */
99 iwe.cmd = SIOCGIWMODE;
100 if (network->capability &
Larry Finger94a79942011-08-23 19:00:42 -0500101 (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) {
102 if (network->capability & WLAN_CAPABILITY_ESS)
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700103 iwe.u.mode = IW_MODE_MASTER;
104 else
105 iwe.u.mode = IW_MODE_ADHOC;
Larry Finger62f27cc2011-08-25 11:48:29 -0500106 start = iwe_stream_add_event_rsl(info, start, stop,
107 &iwe, IW_EV_UINT_LEN);
108 }
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700109
Larry Finger62f27cc2011-08-25 11:48:29 -0500110 /* Add frequency/channel */
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700111 iwe.cmd = SIOCGIWFREQ;
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700112 iwe.u.freq.m = network->channel;
113 iwe.u.freq.e = 0;
114 iwe.u.freq.i = 0;
Larry Finger62f27cc2011-08-25 11:48:29 -0500115 start = iwe_stream_add_event_rsl(info, start, stop, &iwe,
116 IW_EV_FREQ_LEN);
Larry Finger94a79942011-08-23 19:00:42 -0500117
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700118 /* Add encryption capability */
119 iwe.cmd = SIOCGIWENCODE;
120 if (network->capability & WLAN_CAPABILITY_PRIVACY)
121 iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
122 else
123 iwe.u.data.flags = IW_ENCODE_DISABLED;
124 iwe.u.data.length = 0;
Larry Finger62f27cc2011-08-25 11:48:29 -0500125 start = iwe_stream_add_point_rsl(info, start, stop,
126 &iwe, network->ssid);
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700127 /* Add basic and extended rates */
128 max_rate = 0;
129 p = custom;
130 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), " Rates (Mb/s): ");
Larry Finger62f27cc2011-08-25 11:48:29 -0500131 for (i = 0, j = 0; i < network->rates_len;) {
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700132 if (j < network->rates_ex_len &&
133 ((network->rates_ex[j] & 0x7F) <
134 (network->rates[i] & 0x7F)))
135 rate = network->rates_ex[j++] & 0x7F;
136 else
137 rate = network->rates[i++] & 0x7F;
138 if (rate > max_rate)
139 max_rate = rate;
140 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
141 "%d%s ", rate >> 1, (rate & 1) ? ".5" : "");
142 }
143 for (; j < network->rates_ex_len; j++) {
144 rate = network->rates_ex[j] & 0x7F;
145 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
146 "%d%s ", rate >> 1, (rate & 1) ? ".5" : "");
147 if (rate > max_rate)
148 max_rate = rate;
149 }
150
Larry Finger62f27cc2011-08-25 11:48:29 -0500151 if (network->mode >= IEEE_N_24G) {
Larry Fingere92b71d2011-07-18 20:34:19 -0500152 struct ht_capab_ele *ht_cap = NULL;
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700153 bool is40M = false, isShortGI = false;
154 u8 max_mcs = 0;
Matthew Casey3a6b70c2014-08-22 06:27:52 -0400155
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700156 if (!memcmp(network->bssht.bdHTCapBuf, EWC11NHTCap, 4))
Larry Finger62f27cc2011-08-25 11:48:29 -0500157 ht_cap = (struct ht_capab_ele *)
158 &network->bssht.bdHTCapBuf[4];
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700159 else
Larry Finger62f27cc2011-08-25 11:48:29 -0500160 ht_cap = (struct ht_capab_ele *)
161 &network->bssht.bdHTCapBuf[0];
162 is40M = (ht_cap->ChlWidth) ? 1 : 0;
163 isShortGI = (ht_cap->ChlWidth) ?
164 ((ht_cap->ShortGI40Mhz) ? 1 : 0) :
165 ((ht_cap->ShortGI20Mhz) ? 1 : 0);
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700166
Larry Finger62f27cc2011-08-25 11:48:29 -0500167 max_mcs = HTGetHighestMCSRate(ieee, ht_cap->MCS,
168 MCS_FILTER_ALL);
169 rate = MCS_DATA_RATE[is40M][isShortGI][max_mcs & 0x7f];
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700170 if (rate > max_rate)
171 max_rate = rate;
172 }
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700173 iwe.cmd = SIOCGIWRATE;
174 iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
175 iwe.u.bitrate.value = max_rate * 500000;
Larry Finger94a79942011-08-23 19:00:42 -0500176 start = iwe_stream_add_event_rsl(info, start, stop, &iwe,
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700177 IW_EV_PARAM_LEN);
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700178 iwe.cmd = IWEVCUSTOM;
179 iwe.u.data.length = p - custom;
180 if (iwe.u.data.length)
Larry Finger62f27cc2011-08-25 11:48:29 -0500181 start = iwe_stream_add_point_rsl(info, start, stop,
182 &iwe, custom);
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700183 /* Add quality statistics */
184 /* TODO: Fix these values... */
185 iwe.cmd = IWEVQUAL;
186 iwe.u.qual.qual = network->stats.signal;
187 iwe.u.qual.level = network->stats.rssi;
188 iwe.u.qual.noise = network->stats.noise;
Larry Finger94a79942011-08-23 19:00:42 -0500189 iwe.u.qual.updated = network->stats.mask & RTLLIB_STATMASK_WEMASK;
190 if (!(network->stats.mask & RTLLIB_STATMASK_RSSI))
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700191 iwe.u.qual.updated |= IW_QUAL_LEVEL_INVALID;
Larry Finger94a79942011-08-23 19:00:42 -0500192 if (!(network->stats.mask & RTLLIB_STATMASK_NOISE))
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700193 iwe.u.qual.updated |= IW_QUAL_NOISE_INVALID;
Larry Finger94a79942011-08-23 19:00:42 -0500194 if (!(network->stats.mask & RTLLIB_STATMASK_SIGNAL))
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700195 iwe.u.qual.updated |= IW_QUAL_QUAL_INVALID;
196 iwe.u.qual.updated = 7;
Larry Finger62f27cc2011-08-25 11:48:29 -0500197 start = iwe_stream_add_event_rsl(info, start, stop, &iwe,
198 IW_EV_QUAL_LEN);
Larry Finger94a79942011-08-23 19:00:42 -0500199
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700200 iwe.cmd = IWEVCUSTOM;
201 p = custom;
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700202 iwe.u.data.length = p - custom;
203 if (iwe.u.data.length)
Larry Finger62f27cc2011-08-25 11:48:29 -0500204 start = iwe_stream_add_point_rsl(info, start, stop,
205 &iwe, custom);
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700206
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700207 memset(&iwe, 0, sizeof(iwe));
Larry Finger62f27cc2011-08-25 11:48:29 -0500208 if (network->wpa_ie_len) {
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700209 char buf[MAX_WPA_IE_LEN];
Matthew Casey3a6b70c2014-08-22 06:27:52 -0400210
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700211 memcpy(buf, network->wpa_ie, network->wpa_ie_len);
212 iwe.cmd = IWEVGENIE;
213 iwe.u.data.length = network->wpa_ie_len;
Larry Finger94a79942011-08-23 19:00:42 -0500214 start = iwe_stream_add_point_rsl(info, start, stop, &iwe, buf);
Larry Finger62f27cc2011-08-25 11:48:29 -0500215 }
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700216 memset(&iwe, 0, sizeof(iwe));
Larry Finger62f27cc2011-08-25 11:48:29 -0500217 if (network->rsn_ie_len) {
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700218 char buf[MAX_WPA_IE_LEN];
Matthew Casey3a6b70c2014-08-22 06:27:52 -0400219
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700220 memcpy(buf, network->rsn_ie, network->rsn_ie_len);
221 iwe.cmd = IWEVGENIE;
222 iwe.u.data.length = network->rsn_ie_len;
Larry Finger94a79942011-08-23 19:00:42 -0500223 start = iwe_stream_add_point_rsl(info, start, stop, &iwe, buf);
Larry Finger62f27cc2011-08-25 11:48:29 -0500224 }
Larry Finger94a79942011-08-23 19:00:42 -0500225
Larry Finger94a79942011-08-23 19:00:42 -0500226 /* add info for WZC */
227 memset(&iwe, 0, sizeof(iwe));
Larry Finger62f27cc2011-08-25 11:48:29 -0500228 if (network->wzc_ie_len) {
Larry Finger94a79942011-08-23 19:00:42 -0500229 char buf[MAX_WZC_IE_LEN];
Matthew Casey3a6b70c2014-08-22 06:27:52 -0400230
Larry Finger94a79942011-08-23 19:00:42 -0500231 memcpy(buf, network->wzc_ie, network->wzc_ie_len);
232 iwe.cmd = IWEVGENIE;
233 iwe.u.data.length = network->wzc_ie_len;
234 start = iwe_stream_add_point_rsl(info, start, stop, &iwe, buf);
Larry Finger62f27cc2011-08-25 11:48:29 -0500235 }
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700236
237 /* Add EXTRA: Age to display seconds since last beacon/probe response
Mateusz Kulikowski14b40d92015-04-01 00:24:37 +0200238 * for given network.
239 */
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700240 iwe.cmd = IWEVCUSTOM;
241 p = custom;
242 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
Larry Finger62f27cc2011-08-25 11:48:29 -0500243 " Last beacon: %lums ago",
244 (jiffies - network->last_scanned) / (HZ / 100));
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700245 iwe.u.data.length = p - custom;
246 if (iwe.u.data.length)
Larry Finger62f27cc2011-08-25 11:48:29 -0500247 start = iwe_stream_add_point_rsl(info, start, stop,
248 &iwe, custom);
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700249
250 return start;
251}
252
Larry Finger94a79942011-08-23 19:00:42 -0500253int rtllib_wx_get_scan(struct rtllib_device *ieee,
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700254 struct iw_request_info *info,
255 union iwreq_data *wrqu, char *extra)
256{
Larry Finger94a79942011-08-23 19:00:42 -0500257 struct rtllib_network *network;
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700258 unsigned long flags;
259
260 char *ev = extra;
Larry Finger94a79942011-08-23 19:00:42 -0500261 char *stop = ev + wrqu->data.length;
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700262 int i = 0;
263 int err = 0;
Matthew Casey3a6b70c2014-08-22 06:27:52 -0400264
Mateusz Kulikowskic6a91ab2015-05-31 20:19:28 +0200265 netdev_dbg(ieee->dev, "Getting scan\n");
Binoy Jayan9afa9372016-06-01 14:56:52 +0530266 mutex_lock(&ieee->wx_mutex);
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700267 spin_lock_irqsave(&ieee->lock, flags);
268
269 list_for_each_entry(network, &ieee->network_list, list) {
270 i++;
Larry Finger62f27cc2011-08-25 11:48:29 -0500271 if ((stop - ev) < 200) {
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700272 err = -E2BIG;
273 break;
Larry Finger62f27cc2011-08-25 11:48:29 -0500274 }
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700275 if (ieee->scan_age == 0 ||
276 time_after(network->last_scanned + ieee->scan_age, jiffies))
Larry Finger62f27cc2011-08-25 11:48:29 -0500277 ev = rtl819x_translate_scan(ieee, ev, stop, network,
278 info);
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700279 else
Mateusz Kulikowski521a9cb2015-05-31 20:19:30 +0200280 netdev_dbg(ieee->dev,
281 "Network '%s ( %pM)' hidden due to age (%lums).\n",
282 escape_essid(network->ssid,
283 network->ssid_len),
284 network->bssid,
285 (jiffies - network->last_scanned) /
286 (HZ / 100));
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700287 }
288
289 spin_unlock_irqrestore(&ieee->lock, flags);
Binoy Jayan9afa9372016-06-01 14:56:52 +0530290 mutex_unlock(&ieee->wx_mutex);
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700291 wrqu->data.length = ev - extra;
292 wrqu->data.flags = 0;
293
Mateusz Kulikowskic6a91ab2015-05-31 20:19:28 +0200294 netdev_dbg(ieee->dev, "%s(): %d networks returned.\n", __func__, i);
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700295
296 return err;
297}
Sean MacLennan3b284992011-11-28 20:20:26 -0500298EXPORT_SYMBOL(rtllib_wx_get_scan);
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700299
Larry Finger94a79942011-08-23 19:00:42 -0500300int rtllib_wx_set_encode(struct rtllib_device *ieee,
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700301 struct iw_request_info *info,
302 union iwreq_data *wrqu, char *keybuf)
303{
304 struct iw_point *erq = &(wrqu->encoding);
305 struct net_device *dev = ieee->dev;
Larry Finger94a79942011-08-23 19:00:42 -0500306 struct rtllib_security sec = {
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700307 .flags = 0
308 };
309 int i, key, key_provided, len;
Sean MacLennan32c44cb2011-12-19 23:20:41 -0500310 struct lib80211_crypt_data **crypt;
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700311
Mateusz Kulikowskic6a91ab2015-05-31 20:19:28 +0200312 netdev_dbg(ieee->dev, "%s()\n", __func__);
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700313
314 key = erq->flags & IW_ENCODE_INDEX;
315 if (key) {
Sean MacLennan184f1932011-12-19 23:19:23 -0500316 if (key > NUM_WEP_KEYS)
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700317 return -EINVAL;
318 key--;
319 key_provided = 1;
320 } else {
321 key_provided = 0;
Sean MacLennan0ddcf5f2011-12-19 23:21:41 -0500322 key = ieee->crypt_info.tx_keyidx;
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700323 }
324
Mateusz Kulikowskic6a91ab2015-05-31 20:19:28 +0200325 netdev_dbg(ieee->dev, "Key: %d [%s]\n", key, key_provided ?
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700326 "provided" : "default");
Sean MacLennan0ddcf5f2011-12-19 23:21:41 -0500327 crypt = &ieee->crypt_info.crypt[key];
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700328 if (erq->flags & IW_ENCODE_DISABLED) {
329 if (key_provided && *crypt) {
Mateusz Kulikowskic6a91ab2015-05-31 20:19:28 +0200330 netdev_dbg(ieee->dev,
331 "Disabling encryption on key %d.\n", key);
Sean MacLennan3b148be2011-12-19 23:23:08 -0500332 lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700333 } else
Mateusz Kulikowskic6a91ab2015-05-31 20:19:28 +0200334 netdev_dbg(ieee->dev, "Disabling encryption.\n");
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700335
336 /* Check all the keys to see if any are still configured,
Mateusz Kulikowski14b40d92015-04-01 00:24:37 +0200337 * and if no key index was provided, de-init them all
338 */
Sean MacLennan184f1932011-12-19 23:19:23 -0500339 for (i = 0; i < NUM_WEP_KEYS; i++) {
Sean MacLennan0ddcf5f2011-12-19 23:21:41 -0500340 if (ieee->crypt_info.crypt[i] != NULL) {
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700341 if (key_provided)
342 break;
Sean MacLennan3b148be2011-12-19 23:23:08 -0500343 lib80211_crypt_delayed_deinit(&ieee->crypt_info,
Ksenija Stanojevica3ed22e2015-02-28 19:47:53 +0100344 &ieee->crypt_info.crypt[i]);
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700345 }
346 }
347
Sean MacLennan184f1932011-12-19 23:19:23 -0500348 if (i == NUM_WEP_KEYS) {
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700349 sec.enabled = 0;
350 sec.level = SEC_LEVEL_0;
351 sec.flags |= SEC_ENABLED | SEC_LEVEL;
352 }
353
354 goto done;
355 }
356
357
358
359 sec.enabled = 1;
360 sec.flags |= SEC_ENABLED;
361
362 if (*crypt != NULL && (*crypt)->ops != NULL &&
Sean MacLennan3b148be2011-12-19 23:23:08 -0500363 strcmp((*crypt)->ops->name, "R-WEP") != 0) {
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700364 /* changing to use WEP; deinit previously used algorithm
Mateusz Kulikowski14b40d92015-04-01 00:24:37 +0200365 * on this key
366 */
Sean MacLennan3b148be2011-12-19 23:23:08 -0500367 lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700368 }
369
370 if (*crypt == NULL) {
Sean MacLennan32c44cb2011-12-19 23:20:41 -0500371 struct lib80211_crypt_data *new_crypt;
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700372
373 /* take WEP into use */
Sean MacLennan32c44cb2011-12-19 23:20:41 -0500374 new_crypt = kzalloc(sizeof(struct lib80211_crypt_data),
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700375 GFP_KERNEL);
376 if (new_crypt == NULL)
377 return -ENOMEM;
Sean MacLennan3b148be2011-12-19 23:23:08 -0500378 new_crypt->ops = lib80211_get_crypto_ops("R-WEP");
Larry Finger94a79942011-08-23 19:00:42 -0500379 if (!new_crypt->ops) {
380 request_module("rtllib_crypt_wep");
Sean MacLennan3b148be2011-12-19 23:23:08 -0500381 new_crypt->ops = lib80211_get_crypto_ops("R-WEP");
Larry Finger94a79942011-08-23 19:00:42 -0500382 }
383
Herton Ronaldo Krzesinskia010a332009-10-02 11:03:38 -0300384 if (new_crypt->ops)
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700385 new_crypt->priv = new_crypt->ops->init(key);
386
387 if (!new_crypt->ops || !new_crypt->priv) {
388 kfree(new_crypt);
389 new_crypt = NULL;
390
Mateusz Kulikowskid69d2052015-03-17 00:00:52 +0100391 netdev_warn(dev,
392 "%s: could not initialize WEP: load module rtllib_crypt_wep\n",
393 dev->name);
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700394 return -EOPNOTSUPP;
395 }
396 *crypt = new_crypt;
397 }
398
399 /* If a new key was provided, set it up */
400 if (erq->length > 0) {
401 len = erq->length <= 5 ? 5 : 13;
402 memcpy(sec.keys[key], keybuf, erq->length);
403 if (len > erq->length)
404 memset(sec.keys[key] + erq->length, 0,
405 len - erq->length);
Mateusz Kulikowskic6a91ab2015-05-31 20:19:28 +0200406 netdev_dbg(ieee->dev, "Setting key %d to '%s' (%d:%d bytes)\n",
407 key, escape_essid(sec.keys[key], len), erq->length,
408 len);
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700409 sec.key_sizes[key] = len;
Larry Finger94a79942011-08-23 19:00:42 -0500410 (*crypt)->ops->set_key(sec.keys[key], len, NULL,
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700411 (*crypt)->priv);
412 sec.flags |= (1 << key);
413 /* This ensures a key will be activated if no key is
Mateusz Kulikowski14b40d92015-04-01 00:24:37 +0200414 * explicitly set
415 */
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700416 if (key == sec.active_key)
417 sec.flags |= SEC_ACTIVE_KEY;
Sean MacLennan0ddcf5f2011-12-19 23:21:41 -0500418 ieee->crypt_info.tx_keyidx = key;
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700419
420 } else {
421 len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN,
422 NULL, (*crypt)->priv);
423 if (len == 0) {
424 /* Set a default key of all 0 */
Ksenija Stanojevicc60cfc82015-02-28 19:20:36 +0100425 netdev_info(ieee->dev, "Setting key %d to all zero.\n",
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700426 key);
427
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700428 memset(sec.keys[key], 0, 13);
429 (*crypt)->ops->set_key(sec.keys[key], 13, NULL,
430 (*crypt)->priv);
431 sec.key_sizes[key] = 13;
432 sec.flags |= (1 << key);
433 }
434
435 /* No key data - just set the default TX key index */
436 if (key_provided) {
Mateusz Kulikowskic6a91ab2015-05-31 20:19:28 +0200437 netdev_dbg(ieee->dev,
438 "Setting key %d as default Tx key.\n", key);
Sean MacLennan0ddcf5f2011-12-19 23:21:41 -0500439 ieee->crypt_info.tx_keyidx = key;
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700440 sec.active_key = key;
441 sec.flags |= SEC_ACTIVE_KEY;
442 }
443 }
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700444 done:
445 ieee->open_wep = !(erq->flags & IW_ENCODE_RESTRICTED);
Larry Finger62f27cc2011-08-25 11:48:29 -0500446 ieee->auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN :
447 WLAN_AUTH_SHARED_KEY;
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700448 sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY;
449 sec.flags |= SEC_AUTH_MODE;
Mateusz Kulikowskic6a91ab2015-05-31 20:19:28 +0200450 netdev_dbg(ieee->dev, "Auth: %s\n", sec.auth_mode == WLAN_AUTH_OPEN ?
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700451 "OPEN" : "SHARED KEY");
452
453 /* For now we just support WEP, so only set that security level...
Mateusz Kulikowski14b40d92015-04-01 00:24:37 +0200454 * TODO: When WPA is added this is one place that needs to change
455 */
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700456 sec.flags |= SEC_LEVEL;
457 sec.level = SEC_LEVEL_1; /* 40 and 104 bit WEP */
458
459 if (ieee->set_security)
Larry Finger94a79942011-08-23 19:00:42 -0500460 ieee->set_security(dev, &sec);
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700461
462 /* Do not reset port if card is in Managed mode since resetting will
463 * generate new IEEE 802.11 authentication which may end up in looping
464 * with IEEE 802.1X. If your hardware requires a reset after WEP
465 * configuration (for example... Prism2), implement the reset_port in
Mateusz Kulikowski14b40d92015-04-01 00:24:37 +0200466 * the callbacks structures used to initialize the 802.11 stack.
467 */
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700468 if (ieee->reset_on_keychange &&
469 ieee->iw_mode != IW_MODE_INFRA &&
Larry Finger94a79942011-08-23 19:00:42 -0500470 ieee->reset_port && ieee->reset_port(dev)) {
Ksenija Stanojevicc60cfc82015-02-28 19:20:36 +0100471 netdev_dbg(dev, "%s: reset_port failed\n", dev->name);
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700472 return -EINVAL;
473 }
474 return 0;
475}
Sean MacLennan3b284992011-11-28 20:20:26 -0500476EXPORT_SYMBOL(rtllib_wx_set_encode);
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700477
Larry Finger94a79942011-08-23 19:00:42 -0500478int rtllib_wx_get_encode(struct rtllib_device *ieee,
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700479 struct iw_request_info *info,
480 union iwreq_data *wrqu, char *keybuf)
481{
482 struct iw_point *erq = &(wrqu->encoding);
483 int len, key;
Sean MacLennan32c44cb2011-12-19 23:20:41 -0500484 struct lib80211_crypt_data *crypt;
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700485
Mateusz Kulikowskic6a91ab2015-05-31 20:19:28 +0200486 netdev_dbg(ieee->dev, "%s()\n", __func__);
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700487
Larry Finger94a79942011-08-23 19:00:42 -0500488 if (ieee->iw_mode == IW_MODE_MONITOR)
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700489 return -1;
490
491 key = erq->flags & IW_ENCODE_INDEX;
492 if (key) {
Sean MacLennan184f1932011-12-19 23:19:23 -0500493 if (key > NUM_WEP_KEYS)
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700494 return -EINVAL;
495 key--;
Larry Finger94a79942011-08-23 19:00:42 -0500496 } else {
Sean MacLennan0ddcf5f2011-12-19 23:21:41 -0500497 key = ieee->crypt_info.tx_keyidx;
Larry Finger94a79942011-08-23 19:00:42 -0500498 }
Sean MacLennan0ddcf5f2011-12-19 23:21:41 -0500499 crypt = ieee->crypt_info.crypt[key];
Larry Finger94a79942011-08-23 19:00:42 -0500500
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700501 erq->flags = key + 1;
502
503 if (crypt == NULL || crypt->ops == NULL) {
504 erq->length = 0;
505 erq->flags |= IW_ENCODE_DISABLED;
506 return 0;
507 }
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700508 len = crypt->ops->get_key(keybuf, SCM_KEY_LEN, NULL, crypt->priv);
Mateusz Kulikowski622fd492015-05-31 20:19:47 +0200509
510 erq->length = max(len, 0);
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700511
512 erq->flags |= IW_ENCODE_ENABLED;
513
514 if (ieee->open_wep)
515 erq->flags |= IW_ENCODE_OPEN;
516 else
517 erq->flags |= IW_ENCODE_RESTRICTED;
518
519 return 0;
520}
Sean MacLennan3b284992011-11-28 20:20:26 -0500521EXPORT_SYMBOL(rtllib_wx_get_encode);
Mike McCormack35917332011-07-11 08:56:03 +0900522
Larry Finger94a79942011-08-23 19:00:42 -0500523int rtllib_wx_set_encode_ext(struct rtllib_device *ieee,
Larry Finger62f27cc2011-08-25 11:48:29 -0500524 struct iw_request_info *info,
525 union iwreq_data *wrqu, char *extra)
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700526{
527 int ret = 0;
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700528 struct net_device *dev = ieee->dev;
Larry Finger62f27cc2011-08-25 11:48:29 -0500529 struct iw_point *encoding = &wrqu->encoding;
530 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
531 int i, idx;
532 int group_key = 0;
533 const char *alg, *module;
Sean MacLennan32c44cb2011-12-19 23:20:41 -0500534 struct lib80211_crypto_ops *ops;
535 struct lib80211_crypt_data **crypt;
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700536
Larry Finger62f27cc2011-08-25 11:48:29 -0500537 struct rtllib_security sec = {
538 .flags = 0,
539 };
540 idx = encoding->flags & IW_ENCODE_INDEX;
541 if (idx) {
Sean MacLennan184f1932011-12-19 23:19:23 -0500542 if (idx < 1 || idx > NUM_WEP_KEYS)
Larry Finger62f27cc2011-08-25 11:48:29 -0500543 return -EINVAL;
544 idx--;
Larry Finger94a79942011-08-23 19:00:42 -0500545 } else{
Sean MacLennan0ddcf5f2011-12-19 23:21:41 -0500546 idx = ieee->crypt_info.tx_keyidx;
Larry Finger94a79942011-08-23 19:00:42 -0500547 }
548 if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
Sean MacLennan0ddcf5f2011-12-19 23:21:41 -0500549 crypt = &ieee->crypt_info.crypt[idx];
Larry Finger94a79942011-08-23 19:00:42 -0500550 group_key = 1;
551 } else {
552 /* some Cisco APs use idx>0 for unicast in dynamic WEP */
553 if (idx != 0 && ext->alg != IW_ENCODE_ALG_WEP)
Larry Finger62f27cc2011-08-25 11:48:29 -0500554 return -EINVAL;
Larry Finger94a79942011-08-23 19:00:42 -0500555 if (ieee->iw_mode == IW_MODE_INFRA)
Sean MacLennan0ddcf5f2011-12-19 23:21:41 -0500556 crypt = &ieee->crypt_info.crypt[idx];
Larry Finger94a79942011-08-23 19:00:42 -0500557 else
558 return -EINVAL;
559 }
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700560
Larry Finger94a79942011-08-23 19:00:42 -0500561 sec.flags |= SEC_ENABLED;
562 if ((encoding->flags & IW_ENCODE_DISABLED) ||
Larry Finger62f27cc2011-08-25 11:48:29 -0500563 ext->alg == IW_ENCODE_ALG_NONE) {
Larry Finger94a79942011-08-23 19:00:42 -0500564 if (*crypt)
Sean MacLennan3b148be2011-12-19 23:23:08 -0500565 lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700566
Sean MacLennan184f1932011-12-19 23:19:23 -0500567 for (i = 0; i < NUM_WEP_KEYS; i++) {
Sean MacLennan0ddcf5f2011-12-19 23:21:41 -0500568 if (ieee->crypt_info.crypt[i] != NULL)
Larry Finger94a79942011-08-23 19:00:42 -0500569 break;
570 }
Sean MacLennan184f1932011-12-19 23:19:23 -0500571 if (i == NUM_WEP_KEYS) {
Larry Finger94a79942011-08-23 19:00:42 -0500572 sec.enabled = 0;
573 sec.level = SEC_LEVEL_0;
574 sec.flags |= SEC_LEVEL;
575 }
576 goto done;
577 }
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700578
579 sec.enabled = 1;
Larry Finger62f27cc2011-08-25 11:48:29 -0500580 switch (ext->alg) {
581 case IW_ENCODE_ALG_WEP:
Sean MacLennan3b148be2011-12-19 23:23:08 -0500582 alg = "R-WEP";
Larry Finger62f27cc2011-08-25 11:48:29 -0500583 module = "rtllib_crypt_wep";
584 break;
585 case IW_ENCODE_ALG_TKIP:
Sean MacLennan3b148be2011-12-19 23:23:08 -0500586 alg = "R-TKIP";
Larry Finger62f27cc2011-08-25 11:48:29 -0500587 module = "rtllib_crypt_tkip";
588 break;
589 case IW_ENCODE_ALG_CCMP:
Sean MacLennan3b148be2011-12-19 23:23:08 -0500590 alg = "R-CCMP";
Larry Finger62f27cc2011-08-25 11:48:29 -0500591 module = "rtllib_crypt_ccmp";
592 break;
593 default:
Mateusz Kulikowskic6a91ab2015-05-31 20:19:28 +0200594 netdev_dbg(ieee->dev, "Unknown crypto alg %d\n", ext->alg);
Larry Finger62f27cc2011-08-25 11:48:29 -0500595 ret = -EINVAL;
596 goto done;
597 }
Ksenija Stanojevicc60cfc82015-02-28 19:20:36 +0100598 netdev_info(dev, "alg name:%s\n", alg);
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700599
Sean MacLennan3b148be2011-12-19 23:23:08 -0500600 ops = lib80211_get_crypto_ops(alg);
Larry Finger62f27cc2011-08-25 11:48:29 -0500601 if (ops == NULL) {
602 char tempbuf[100];
Larry Finger94a79942011-08-23 19:00:42 -0500603
Larry Finger62f27cc2011-08-25 11:48:29 -0500604 memset(tempbuf, 0x00, 100);
605 sprintf(tempbuf, "%s", module);
606 request_module("%s", tempbuf);
Sean MacLennan3b148be2011-12-19 23:23:08 -0500607 ops = lib80211_get_crypto_ops(alg);
Larry Finger62f27cc2011-08-25 11:48:29 -0500608 }
609 if (ops == NULL) {
Ksenija Stanojevicc60cfc82015-02-28 19:20:36 +0100610 netdev_info(dev, "========>unknown crypto alg %d\n", ext->alg);
Larry Finger62f27cc2011-08-25 11:48:29 -0500611 ret = -EINVAL;
612 goto done;
613 }
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700614
Larry Finger62f27cc2011-08-25 11:48:29 -0500615 if (*crypt == NULL || (*crypt)->ops != ops) {
Sean MacLennan32c44cb2011-12-19 23:20:41 -0500616 struct lib80211_crypt_data *new_crypt;
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700617
Sean MacLennan3b148be2011-12-19 23:23:08 -0500618 lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700619
Larry Finger62f27cc2011-08-25 11:48:29 -0500620 new_crypt = kzalloc(sizeof(*new_crypt), GFP_KERNEL);
621 if (new_crypt == NULL) {
622 ret = -ENOMEM;
623 goto done;
624 }
625 new_crypt->ops = ops;
Sean MacLennan0bd35532015-11-15 19:51:43 -0500626 if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
Larry Finger62f27cc2011-08-25 11:48:29 -0500627 new_crypt->priv = new_crypt->ops->init(idx);
Larry Finger94a79942011-08-23 19:00:42 -0500628
Larry Finger62f27cc2011-08-25 11:48:29 -0500629 if (new_crypt->priv == NULL) {
630 kfree(new_crypt);
631 ret = -EINVAL;
632 goto done;
633 }
634 *crypt = new_crypt;
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700635
Larry Finger94a79942011-08-23 19:00:42 -0500636 }
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700637
Larry Finger62f27cc2011-08-25 11:48:29 -0500638 if (ext->key_len > 0 && (*crypt)->ops->set_key &&
639 (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq,
640 (*crypt)->priv) < 0) {
Ksenija Stanojevicc60cfc82015-02-28 19:20:36 +0100641 netdev_info(dev, "key setting failed\n");
Larry Finger62f27cc2011-08-25 11:48:29 -0500642 ret = -EINVAL;
643 goto done;
644 }
645 if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
Sean MacLennan0ddcf5f2011-12-19 23:21:41 -0500646 ieee->crypt_info.tx_keyidx = idx;
Larry Finger62f27cc2011-08-25 11:48:29 -0500647 sec.active_key = idx;
648 sec.flags |= SEC_ACTIVE_KEY;
649 }
650 if (ext->alg != IW_ENCODE_ALG_NONE) {
651 sec.key_sizes[idx] = ext->key_len;
652 sec.flags |= (1 << idx);
653 if (ext->alg == IW_ENCODE_ALG_WEP) {
654 sec.flags |= SEC_LEVEL;
655 sec.level = SEC_LEVEL_1;
656 } else if (ext->alg == IW_ENCODE_ALG_TKIP) {
657 sec.flags |= SEC_LEVEL;
658 sec.level = SEC_LEVEL_2;
659 } else if (ext->alg == IW_ENCODE_ALG_CCMP) {
660 sec.flags |= SEC_LEVEL;
661 sec.level = SEC_LEVEL_3;
662 }
663 /* Don't set sec level for group keys. */
664 if (group_key)
665 sec.flags &= ~SEC_LEVEL;
666 }
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700667done:
Larry Finger62f27cc2011-08-25 11:48:29 -0500668 if (ieee->set_security)
669 ieee->set_security(ieee->dev, &sec);
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700670
671 if (ieee->reset_on_keychange &&
Larry Finger62f27cc2011-08-25 11:48:29 -0500672 ieee->iw_mode != IW_MODE_INFRA &&
673 ieee->reset_port && ieee->reset_port(dev)) {
Mateusz Kulikowskic6a91ab2015-05-31 20:19:28 +0200674 netdev_dbg(ieee->dev, "Port reset failed\n");
Larry Finger62f27cc2011-08-25 11:48:29 -0500675 return -EINVAL;
676 }
677 return ret;
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700678}
Sean MacLennan3b284992011-11-28 20:20:26 -0500679EXPORT_SYMBOL(rtllib_wx_set_encode_ext);
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700680
Larry Finger94a79942011-08-23 19:00:42 -0500681int rtllib_wx_set_mlme(struct rtllib_device *ieee,
Larry Finger62f27cc2011-08-25 11:48:29 -0500682 struct iw_request_info *info,
683 union iwreq_data *wrqu, char *extra)
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700684{
Larry Finger94a79942011-08-23 19:00:42 -0500685 u8 i = 0;
686 bool deauth = false;
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700687 struct iw_mlme *mlme = (struct iw_mlme *) extra;
Larry Finger94a79942011-08-23 19:00:42 -0500688
689 if (ieee->state != RTLLIB_LINKED)
690 return -ENOLINK;
691
Binoy Jayan9afa9372016-06-01 14:56:52 +0530692 mutex_lock(&ieee->wx_mutex);
Larry Finger94a79942011-08-23 19:00:42 -0500693
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700694 switch (mlme->cmd) {
Larry Finger62f27cc2011-08-25 11:48:29 -0500695 case IW_MLME_DEAUTH:
696 deauth = true;
697 /* leave break out intentionly */
Larry Finger94a79942011-08-23 19:00:42 -0500698
Larry Finger62f27cc2011-08-25 11:48:29 -0500699 case IW_MLME_DISASSOC:
Valentina Manea4bb01422013-10-25 11:28:10 +0300700 if (deauth)
Ksenija Stanojevicc60cfc82015-02-28 19:20:36 +0100701 netdev_info(ieee->dev, "disauth packet !\n");
Larry Finger62f27cc2011-08-25 11:48:29 -0500702 else
Ksenija Stanojevicc60cfc82015-02-28 19:20:36 +0100703 netdev_info(ieee->dev, "dis associate packet!\n");
Larry Finger94a79942011-08-23 19:00:42 -0500704
Larry Finger62f27cc2011-08-25 11:48:29 -0500705 ieee->cannot_notify = true;
Larry Finger94a79942011-08-23 19:00:42 -0500706
Larry Finger62f27cc2011-08-25 11:48:29 -0500707 SendDisassociation(ieee, deauth, mlme->reason_code);
708 rtllib_disassociate(ieee);
Larry Finger94a79942011-08-23 19:00:42 -0500709
Larry Finger62f27cc2011-08-25 11:48:29 -0500710 ieee->wap_set = 0;
711 for (i = 0; i < 6; i++)
712 ieee->current_network.bssid[i] = 0x55;
Larry Finger94a79942011-08-23 19:00:42 -0500713
Larry Finger62f27cc2011-08-25 11:48:29 -0500714 ieee->ssid_set = 0;
715 ieee->current_network.ssid[0] = '\0';
716 ieee->current_network.ssid_len = 0;
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700717 break;
Larry Finger94a79942011-08-23 19:00:42 -0500718 default:
Binoy Jayan9afa9372016-06-01 14:56:52 +0530719 mutex_unlock(&ieee->wx_mutex);
Larry Finger94a79942011-08-23 19:00:42 -0500720 return -EOPNOTSUPP;
721 }
722
Binoy Jayan9afa9372016-06-01 14:56:52 +0530723 mutex_unlock(&ieee->wx_mutex);
Larry Finger94a79942011-08-23 19:00:42 -0500724
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700725 return 0;
726}
Sean MacLennan3b284992011-11-28 20:20:26 -0500727EXPORT_SYMBOL(rtllib_wx_set_mlme);
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700728
Larry Finger94a79942011-08-23 19:00:42 -0500729int rtllib_wx_set_auth(struct rtllib_device *ieee,
Larry Finger62f27cc2011-08-25 11:48:29 -0500730 struct iw_request_info *info,
731 struct iw_param *data, char *extra)
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700732{
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700733 switch (data->flags & IW_AUTH_INDEX) {
Larry Finger62f27cc2011-08-25 11:48:29 -0500734 case IW_AUTH_WPA_VERSION:
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700735 break;
Larry Finger62f27cc2011-08-25 11:48:29 -0500736 case IW_AUTH_CIPHER_PAIRWISE:
737 case IW_AUTH_CIPHER_GROUP:
738 case IW_AUTH_KEY_MGMT:
Mateusz Kulikowski14b40d92015-04-01 00:24:37 +0200739 /* Host AP driver does not use these parameters and allows
Larry Finger94a79942011-08-23 19:00:42 -0500740 * wpa_supplicant to control them internally.
741 */
Larry Finger62f27cc2011-08-25 11:48:29 -0500742 break;
743 case IW_AUTH_TKIP_COUNTERMEASURES:
744 ieee->tkip_countermeasures = data->value;
745 break;
746 case IW_AUTH_DROP_UNENCRYPTED:
747 ieee->drop_unencrypted = data->value;
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700748 break;
749
750 case IW_AUTH_80211_AUTH_ALG:
Larry Finger62f27cc2011-08-25 11:48:29 -0500751 if (data->value & IW_AUTH_ALG_SHARED_KEY) {
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700752 ieee->open_wep = 0;
753 ieee->auth_mode = 1;
Larry Finger62f27cc2011-08-25 11:48:29 -0500754 } else if (data->value & IW_AUTH_ALG_OPEN_SYSTEM) {
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700755 ieee->open_wep = 1;
756 ieee->auth_mode = 0;
Larry Finger62f27cc2011-08-25 11:48:29 -0500757 } else if (data->value & IW_AUTH_ALG_LEAP) {
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700758 ieee->open_wep = 1;
759 ieee->auth_mode = 2;
Larry Finger62f27cc2011-08-25 11:48:29 -0500760 } else
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700761 return -EINVAL;
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700762 break;
763
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700764 case IW_AUTH_WPA_ENABLED:
Larry Finger62f27cc2011-08-25 11:48:29 -0500765 ieee->wpa_enabled = (data->value) ? 1 : 0;
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700766 break;
767
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700768 case IW_AUTH_RX_UNENCRYPTED_EAPOL:
Larry Finger62f27cc2011-08-25 11:48:29 -0500769 ieee->ieee802_1x = data->value;
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700770 break;
771 case IW_AUTH_PRIVACY_INVOKED:
772 ieee->privacy_invoked = data->value;
773 break;
774 default:
Larry Finger62f27cc2011-08-25 11:48:29 -0500775 return -EOPNOTSUPP;
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700776 }
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700777 return 0;
778}
Sean MacLennan3b284992011-11-28 20:20:26 -0500779EXPORT_SYMBOL(rtllib_wx_set_auth);
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700780
Larry Finger94a79942011-08-23 19:00:42 -0500781int rtllib_wx_set_gen_ie(struct rtllib_device *ieee, u8 *ie, size_t len)
782{
Larry Finger94a79942011-08-23 19:00:42 -0500783 u8 *buf;
Larry Finger62f27cc2011-08-25 11:48:29 -0500784 u8 eid, wps_oui[4] = {0x0, 0x50, 0xf2, 0x04};
Larry Finger94a79942011-08-23 19:00:42 -0500785
Larry Finger62f27cc2011-08-25 11:48:29 -0500786 if (len > MAX_WPA_IE_LEN || (len && ie == NULL))
Larry Finger94a79942011-08-23 19:00:42 -0500787 return -EINVAL;
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700788
Larry Finger94a79942011-08-23 19:00:42 -0500789 if (len) {
790 eid = ie[0];
Larry Finger62f27cc2011-08-25 11:48:29 -0500791 if ((eid == MFIE_TYPE_GENERIC) && (!memcmp(&ie[2],
792 wps_oui, 4))) {
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700793
Mateusz Kulikowskia5c06ad2015-05-31 20:19:46 +0200794 ieee->wps_ie_len = min_t(size_t, len, MAX_WZC_IE_LEN);
Thomas Meyer23226972011-11-08 20:30:20 +0100795 buf = kmemdup(ie, ieee->wps_ie_len, GFP_KERNEL);
Larry Finger94a79942011-08-23 19:00:42 -0500796 if (buf == NULL)
797 return -ENOMEM;
Larry Finger94a79942011-08-23 19:00:42 -0500798 ieee->wps_ie = buf;
799 return 0;
800 }
801 }
802 ieee->wps_ie_len = 0;
Larry Finger62f27cc2011-08-25 11:48:29 -0500803 kfree(ieee->wps_ie);
Larry Finger94a79942011-08-23 19:00:42 -0500804 ieee->wps_ie = NULL;
805 if (len) {
Larry Finger62f27cc2011-08-25 11:48:29 -0500806 if (len != ie[1]+2)
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700807 return -EINVAL;
Thomas Meyer23226972011-11-08 20:30:20 +0100808 buf = kmemdup(ie, len, GFP_KERNEL);
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700809 if (buf == NULL)
810 return -ENOMEM;
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700811 kfree(ieee->wpa_ie);
812 ieee->wpa_ie = buf;
813 ieee->wpa_ie_len = len;
Larry Finger94a79942011-08-23 19:00:42 -0500814 } else {
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700815 kfree(ieee->wpa_ie);
816 ieee->wpa_ie = NULL;
817 ieee->wpa_ie_len = 0;
818 }
Larry Finger94a79942011-08-23 19:00:42 -0500819 return 0;
820}
Sean MacLennan3b284992011-11-28 20:20:26 -0500821EXPORT_SYMBOL(rtllib_wx_set_gen_ie);