blob: 87ede62657887ef9385aa5006bdf223f073dd0da [file] [log] [blame]
Kalle Valobdcd8172011-07-18 00:22:30 +03001/*
2 * Copyright (c) 2004-2011 Atheros Communications Inc.
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#include "core.h"
18#include "cfg80211.h"
19#include "debug.h"
Kalle Valoabcb3442011-07-22 08:26:20 +030020#include "hif-ops.h"
Kalle Valo003353b0d2011-09-01 10:14:21 +030021#include "testmode.h"
Kalle Valobdcd8172011-07-18 00:22:30 +030022
Jouni Malinen6bbc7c32011-09-05 17:38:47 +030023static unsigned int ath6kl_p2p;
24
25module_param(ath6kl_p2p, uint, 0644);
26
Kalle Valobdcd8172011-07-18 00:22:30 +030027#define RATETAB_ENT(_rate, _rateid, _flags) { \
28 .bitrate = (_rate), \
29 .flags = (_flags), \
30 .hw_value = (_rateid), \
31}
32
33#define CHAN2G(_channel, _freq, _flags) { \
34 .band = IEEE80211_BAND_2GHZ, \
35 .hw_value = (_channel), \
36 .center_freq = (_freq), \
37 .flags = (_flags), \
38 .max_antenna_gain = 0, \
39 .max_power = 30, \
40}
41
42#define CHAN5G(_channel, _flags) { \
43 .band = IEEE80211_BAND_5GHZ, \
44 .hw_value = (_channel), \
45 .center_freq = 5000 + (5 * (_channel)), \
46 .flags = (_flags), \
47 .max_antenna_gain = 0, \
48 .max_power = 30, \
49}
50
51static struct ieee80211_rate ath6kl_rates[] = {
52 RATETAB_ENT(10, 0x1, 0),
53 RATETAB_ENT(20, 0x2, 0),
54 RATETAB_ENT(55, 0x4, 0),
55 RATETAB_ENT(110, 0x8, 0),
56 RATETAB_ENT(60, 0x10, 0),
57 RATETAB_ENT(90, 0x20, 0),
58 RATETAB_ENT(120, 0x40, 0),
59 RATETAB_ENT(180, 0x80, 0),
60 RATETAB_ENT(240, 0x100, 0),
61 RATETAB_ENT(360, 0x200, 0),
62 RATETAB_ENT(480, 0x400, 0),
63 RATETAB_ENT(540, 0x800, 0),
64};
65
66#define ath6kl_a_rates (ath6kl_rates + 4)
67#define ath6kl_a_rates_size 8
68#define ath6kl_g_rates (ath6kl_rates + 0)
69#define ath6kl_g_rates_size 12
70
71static struct ieee80211_channel ath6kl_2ghz_channels[] = {
72 CHAN2G(1, 2412, 0),
73 CHAN2G(2, 2417, 0),
74 CHAN2G(3, 2422, 0),
75 CHAN2G(4, 2427, 0),
76 CHAN2G(5, 2432, 0),
77 CHAN2G(6, 2437, 0),
78 CHAN2G(7, 2442, 0),
79 CHAN2G(8, 2447, 0),
80 CHAN2G(9, 2452, 0),
81 CHAN2G(10, 2457, 0),
82 CHAN2G(11, 2462, 0),
83 CHAN2G(12, 2467, 0),
84 CHAN2G(13, 2472, 0),
85 CHAN2G(14, 2484, 0),
86};
87
88static struct ieee80211_channel ath6kl_5ghz_a_channels[] = {
89 CHAN5G(34, 0), CHAN5G(36, 0),
90 CHAN5G(38, 0), CHAN5G(40, 0),
91 CHAN5G(42, 0), CHAN5G(44, 0),
92 CHAN5G(46, 0), CHAN5G(48, 0),
93 CHAN5G(52, 0), CHAN5G(56, 0),
94 CHAN5G(60, 0), CHAN5G(64, 0),
95 CHAN5G(100, 0), CHAN5G(104, 0),
96 CHAN5G(108, 0), CHAN5G(112, 0),
97 CHAN5G(116, 0), CHAN5G(120, 0),
98 CHAN5G(124, 0), CHAN5G(128, 0),
99 CHAN5G(132, 0), CHAN5G(136, 0),
100 CHAN5G(140, 0), CHAN5G(149, 0),
101 CHAN5G(153, 0), CHAN5G(157, 0),
102 CHAN5G(161, 0), CHAN5G(165, 0),
103 CHAN5G(184, 0), CHAN5G(188, 0),
104 CHAN5G(192, 0), CHAN5G(196, 0),
105 CHAN5G(200, 0), CHAN5G(204, 0),
106 CHAN5G(208, 0), CHAN5G(212, 0),
107 CHAN5G(216, 0),
108};
109
110static struct ieee80211_supported_band ath6kl_band_2ghz = {
111 .n_channels = ARRAY_SIZE(ath6kl_2ghz_channels),
112 .channels = ath6kl_2ghz_channels,
113 .n_bitrates = ath6kl_g_rates_size,
114 .bitrates = ath6kl_g_rates,
115};
116
117static struct ieee80211_supported_band ath6kl_band_5ghz = {
118 .n_channels = ARRAY_SIZE(ath6kl_5ghz_a_channels),
119 .channels = ath6kl_5ghz_a_channels,
120 .n_bitrates = ath6kl_a_rates_size,
121 .bitrates = ath6kl_a_rates,
122};
123
Jouni Malinen837cb972011-10-11 17:31:57 +0300124#define CCKM_KRK_CIPHER_SUITE 0x004096ff /* use for KRK */
125
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530126static int ath6kl_set_wpa_version(struct ath6kl_vif *vif,
Kalle Valobdcd8172011-07-18 00:22:30 +0300127 enum nl80211_wpa_versions wpa_version)
128{
129 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: %u\n", __func__, wpa_version);
130
131 if (!wpa_version) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530132 vif->auth_mode = NONE_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300133 } else if (wpa_version & NL80211_WPA_VERSION_2) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530134 vif->auth_mode = WPA2_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300135 } else if (wpa_version & NL80211_WPA_VERSION_1) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530136 vif->auth_mode = WPA_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300137 } else {
138 ath6kl_err("%s: %u not supported\n", __func__, wpa_version);
139 return -ENOTSUPP;
140 }
141
142 return 0;
143}
144
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530145static int ath6kl_set_auth_type(struct ath6kl_vif *vif,
Kalle Valobdcd8172011-07-18 00:22:30 +0300146 enum nl80211_auth_type auth_type)
147{
Kalle Valobdcd8172011-07-18 00:22:30 +0300148 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: 0x%x\n", __func__, auth_type);
149
150 switch (auth_type) {
151 case NL80211_AUTHTYPE_OPEN_SYSTEM:
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530152 vif->dot11_auth_mode = OPEN_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300153 break;
154 case NL80211_AUTHTYPE_SHARED_KEY:
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530155 vif->dot11_auth_mode = SHARED_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300156 break;
157 case NL80211_AUTHTYPE_NETWORK_EAP:
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530158 vif->dot11_auth_mode = LEAP_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300159 break;
160
161 case NL80211_AUTHTYPE_AUTOMATIC:
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530162 vif->dot11_auth_mode = OPEN_AUTH | SHARED_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300163 break;
164
165 default:
166 ath6kl_err("%s: 0x%x not spported\n", __func__, auth_type);
167 return -ENOTSUPP;
168 }
169
170 return 0;
171}
172
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530173static int ath6kl_set_cipher(struct ath6kl_vif *vif, u32 cipher, bool ucast)
Kalle Valobdcd8172011-07-18 00:22:30 +0300174{
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530175 u8 *ar_cipher = ucast ? &vif->prwise_crypto : &vif->grp_crypto;
176 u8 *ar_cipher_len = ucast ? &vif->prwise_crypto_len :
177 &vif->grp_crypto_len;
Kalle Valobdcd8172011-07-18 00:22:30 +0300178
179 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: cipher 0x%x, ucast %u\n",
180 __func__, cipher, ucast);
181
182 switch (cipher) {
183 case 0:
184 /* our own hack to use value 0 as no crypto used */
185 *ar_cipher = NONE_CRYPT;
186 *ar_cipher_len = 0;
187 break;
188 case WLAN_CIPHER_SUITE_WEP40:
189 *ar_cipher = WEP_CRYPT;
190 *ar_cipher_len = 5;
191 break;
192 case WLAN_CIPHER_SUITE_WEP104:
193 *ar_cipher = WEP_CRYPT;
194 *ar_cipher_len = 13;
195 break;
196 case WLAN_CIPHER_SUITE_TKIP:
197 *ar_cipher = TKIP_CRYPT;
198 *ar_cipher_len = 0;
199 break;
200 case WLAN_CIPHER_SUITE_CCMP:
201 *ar_cipher = AES_CRYPT;
202 *ar_cipher_len = 0;
203 break;
204 default:
205 ath6kl_err("cipher 0x%x not supported\n", cipher);
206 return -ENOTSUPP;
207 }
208
209 return 0;
210}
211
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530212static void ath6kl_set_key_mgmt(struct ath6kl_vif *vif, u32 key_mgmt)
Kalle Valobdcd8172011-07-18 00:22:30 +0300213{
214 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: 0x%x\n", __func__, key_mgmt);
215
216 if (key_mgmt == WLAN_AKM_SUITE_PSK) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530217 if (vif->auth_mode == WPA_AUTH)
218 vif->auth_mode = WPA_PSK_AUTH;
219 else if (vif->auth_mode == WPA2_AUTH)
220 vif->auth_mode = WPA2_PSK_AUTH;
Jouni Malinen837cb972011-10-11 17:31:57 +0300221 } else if (key_mgmt == 0x00409600) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530222 if (vif->auth_mode == WPA_AUTH)
223 vif->auth_mode = WPA_AUTH_CCKM;
224 else if (vif->auth_mode == WPA2_AUTH)
225 vif->auth_mode = WPA2_AUTH_CCKM;
Kalle Valobdcd8172011-07-18 00:22:30 +0300226 } else if (key_mgmt != WLAN_AKM_SUITE_8021X) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530227 vif->auth_mode = NONE_AUTH;
Kalle Valobdcd8172011-07-18 00:22:30 +0300228 }
229}
230
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530231static bool ath6kl_cfg80211_ready(struct ath6kl_vif *vif)
Kalle Valobdcd8172011-07-18 00:22:30 +0300232{
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530233 struct ath6kl *ar = vif->ar;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530234
Kalle Valobdcd8172011-07-18 00:22:30 +0300235 if (!test_bit(WMI_READY, &ar->flag)) {
236 ath6kl_err("wmi is not ready\n");
237 return false;
238 }
239
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530240 if (!test_bit(WLAN_ENABLED, &vif->flags)) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300241 ath6kl_err("wlan disabled\n");
242 return false;
243 }
244
245 return true;
246}
247
Kevin Fang6981ffd2011-10-07 08:51:19 +0800248static bool ath6kl_is_wpa_ie(const u8 *pos)
249{
250 return pos[0] == WLAN_EID_WPA && pos[1] >= 4 &&
251 pos[2] == 0x00 && pos[3] == 0x50 &&
252 pos[4] == 0xf2 && pos[5] == 0x01;
253}
254
255static bool ath6kl_is_rsn_ie(const u8 *pos)
256{
257 return pos[0] == WLAN_EID_RSN;
258}
259
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530260static int ath6kl_set_assoc_req_ies(struct ath6kl_vif *vif, const u8 *ies,
261 size_t ies_len)
Kevin Fang6981ffd2011-10-07 08:51:19 +0800262{
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530263 struct ath6kl *ar = vif->ar;
Kevin Fang6981ffd2011-10-07 08:51:19 +0800264 const u8 *pos;
265 u8 *buf = NULL;
266 size_t len = 0;
267 int ret;
268
269 /*
270 * Filter out RSN/WPA IE(s)
271 */
272
273 if (ies && ies_len) {
274 buf = kmalloc(ies_len, GFP_KERNEL);
275 if (buf == NULL)
276 return -ENOMEM;
277 pos = ies;
278
279 while (pos + 1 < ies + ies_len) {
280 if (pos + 2 + pos[1] > ies + ies_len)
281 break;
282 if (!(ath6kl_is_wpa_ie(pos) || ath6kl_is_rsn_ie(pos))) {
283 memcpy(buf + len, pos, 2 + pos[1]);
284 len += 2 + pos[1];
285 }
286 pos += 2 + pos[1];
287 }
288 }
289
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530290 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
291 WMI_FRAME_ASSOC_REQ, buf, len);
Kevin Fang6981ffd2011-10-07 08:51:19 +0800292 kfree(buf);
293 return ret;
294}
295
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +0530296static int ath6kl_nliftype_to_drv_iftype(enum nl80211_iftype type, u8 *nw_type)
297{
298 switch (type) {
299 case NL80211_IFTYPE_STATION:
300 *nw_type = INFRA_NETWORK;
301 break;
302 case NL80211_IFTYPE_ADHOC:
303 *nw_type = ADHOC_NETWORK;
304 break;
305 case NL80211_IFTYPE_AP:
306 *nw_type = AP_NETWORK;
307 break;
308 case NL80211_IFTYPE_P2P_CLIENT:
309 *nw_type = INFRA_NETWORK;
310 break;
311 case NL80211_IFTYPE_P2P_GO:
312 *nw_type = AP_NETWORK;
313 break;
314 default:
315 ath6kl_err("invalid interface type %u\n", type);
316 return -ENOTSUPP;
317 }
318
319 return 0;
320}
321
322static bool ath6kl_is_valid_iftype(struct ath6kl *ar, enum nl80211_iftype type,
323 u8 *if_idx, u8 *nw_type)
324{
325 int i;
326
327 if (ath6kl_nliftype_to_drv_iftype(type, nw_type))
328 return false;
329
330 if (ar->ibss_if_active || ((type == NL80211_IFTYPE_ADHOC) &&
331 ar->num_vif))
332 return false;
333
334 if (type == NL80211_IFTYPE_STATION ||
335 type == NL80211_IFTYPE_AP || type == NL80211_IFTYPE_ADHOC) {
336 for (i = 0; i < MAX_NUM_VIF; i++) {
337 if ((ar->avail_idx_map >> i) & BIT(0)) {
338 *if_idx = i;
339 return true;
340 }
341 }
342 }
343
344 return false;
345}
346
Kalle Valobdcd8172011-07-18 00:22:30 +0300347static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
348 struct cfg80211_connect_params *sme)
349{
350 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530351 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +0300352 int status;
353
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530354 vif->sme_state = SME_CONNECTING;
Kalle Valobdcd8172011-07-18 00:22:30 +0300355
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530356 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +0300357 return -EIO;
358
359 if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) {
360 ath6kl_err("destroy in progress\n");
361 return -EBUSY;
362 }
363
364 if (test_bit(SKIP_SCAN, &ar->flag) &&
365 ((sme->channel && sme->channel->center_freq == 0) ||
366 (sme->bssid && is_zero_ether_addr(sme->bssid)))) {
367 ath6kl_err("SkipScan: channel or bssid invalid\n");
368 return -EINVAL;
369 }
370
371 if (down_interruptible(&ar->sem)) {
372 ath6kl_err("busy, couldn't get access\n");
373 return -ERESTARTSYS;
374 }
375
376 if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) {
377 ath6kl_err("busy, destroy in progress\n");
378 up(&ar->sem);
379 return -EBUSY;
380 }
381
382 if (ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)]) {
383 /*
384 * sleep until the command queue drains
385 */
386 wait_event_interruptible_timeout(ar->event_wq,
387 ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)] == 0,
388 WMI_TIMEOUT);
389 if (signal_pending(current)) {
390 ath6kl_err("cmd queue drain timeout\n");
391 up(&ar->sem);
392 return -EINTR;
393 }
394 }
395
Kevin Fang6981ffd2011-10-07 08:51:19 +0800396 if (sme->ie && (sme->ie_len > 0)) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530397 status = ath6kl_set_assoc_req_ies(vif, sme->ie, sme->ie_len);
Kevin Fang6981ffd2011-10-07 08:51:19 +0800398 if (status)
399 return status;
400 }
401
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530402 if (test_bit(CONNECTED, &vif->flags) &&
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530403 vif->ssid_len == sme->ssid_len &&
404 !memcmp(vif->ssid, sme->ssid, vif->ssid_len)) {
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +0530405 vif->reconnect_flag = true;
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530406 status = ath6kl_wmi_reconnect_cmd(ar->wmi, vif->fw_vif_idx,
407 vif->req_bssid,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +0530408 vif->ch_hint);
Kalle Valobdcd8172011-07-18 00:22:30 +0300409
410 up(&ar->sem);
411 if (status) {
412 ath6kl_err("wmi_reconnect_cmd failed\n");
413 return -EIO;
414 }
415 return 0;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530416 } else if (vif->ssid_len == sme->ssid_len &&
417 !memcmp(vif->ssid, sme->ssid, vif->ssid_len)) {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530418 ath6kl_disconnect(vif);
Kalle Valobdcd8172011-07-18 00:22:30 +0300419 }
420
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530421 memset(vif->ssid, 0, sizeof(vif->ssid));
422 vif->ssid_len = sme->ssid_len;
423 memcpy(vif->ssid, sme->ssid, sme->ssid_len);
Kalle Valobdcd8172011-07-18 00:22:30 +0300424
425 if (sme->channel)
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +0530426 vif->ch_hint = sme->channel->center_freq;
Kalle Valobdcd8172011-07-18 00:22:30 +0300427
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +0530428 memset(vif->req_bssid, 0, sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +0300429 if (sme->bssid && !is_broadcast_ether_addr(sme->bssid))
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +0530430 memcpy(vif->req_bssid, sme->bssid, sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +0300431
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530432 ath6kl_set_wpa_version(vif, sme->crypto.wpa_versions);
Kalle Valobdcd8172011-07-18 00:22:30 +0300433
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530434 status = ath6kl_set_auth_type(vif, sme->auth_type);
Kalle Valobdcd8172011-07-18 00:22:30 +0300435 if (status) {
436 up(&ar->sem);
437 return status;
438 }
439
440 if (sme->crypto.n_ciphers_pairwise)
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530441 ath6kl_set_cipher(vif, sme->crypto.ciphers_pairwise[0], true);
Kalle Valobdcd8172011-07-18 00:22:30 +0300442 else
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530443 ath6kl_set_cipher(vif, 0, true);
Kalle Valobdcd8172011-07-18 00:22:30 +0300444
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530445 ath6kl_set_cipher(vif, sme->crypto.cipher_group, false);
Kalle Valobdcd8172011-07-18 00:22:30 +0300446
447 if (sme->crypto.n_akm_suites)
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530448 ath6kl_set_key_mgmt(vif, sme->crypto.akm_suites[0]);
Kalle Valobdcd8172011-07-18 00:22:30 +0300449
450 if ((sme->key_len) &&
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530451 (vif->auth_mode == NONE_AUTH) &&
452 (vif->prwise_crypto == WEP_CRYPT)) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300453 struct ath6kl_key *key = NULL;
454
455 if (sme->key_idx < WMI_MIN_KEY_INDEX ||
456 sme->key_idx > WMI_MAX_KEY_INDEX) {
457 ath6kl_err("key index %d out of bounds\n",
458 sme->key_idx);
459 up(&ar->sem);
460 return -ENOENT;
461 }
462
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +0530463 key = &vif->keys[sme->key_idx];
Kalle Valobdcd8172011-07-18 00:22:30 +0300464 key->key_len = sme->key_len;
465 memcpy(key->key, sme->key, key->key_len);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530466 key->cipher = vif->prwise_crypto;
467 vif->def_txkey_index = sme->key_idx;
Kalle Valobdcd8172011-07-18 00:22:30 +0300468
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530469 ath6kl_wmi_addkey_cmd(ar->wmi, vif->fw_vif_idx, sme->key_idx,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530470 vif->prwise_crypto,
Kalle Valobdcd8172011-07-18 00:22:30 +0300471 GROUP_USAGE | TX_USAGE,
472 key->key_len,
473 NULL,
474 key->key, KEY_OP_INIT_VAL, NULL,
475 NO_SYNC_WMIFLAG);
476 }
477
478 if (!ar->usr_bss_filter) {
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530479 clear_bit(CLEAR_BSSFILTER_ON_BEACON, &vif->flags);
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530480 if (ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx,
481 ALL_BSS_FILTER, 0) != 0) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300482 ath6kl_err("couldn't set bss filtering\n");
483 up(&ar->sem);
484 return -EIO;
485 }
486 }
487
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +0530488 vif->nw_type = vif->next_mode;
Kalle Valobdcd8172011-07-18 00:22:30 +0300489
490 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
491 "%s: connect called with authmode %d dot11 auth %d"
492 " PW crypto %d PW crypto len %d GRP crypto %d"
493 " GRP crypto len %d channel hint %u\n",
494 __func__,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530495 vif->auth_mode, vif->dot11_auth_mode, vif->prwise_crypto,
496 vif->prwise_crypto_len, vif->grp_crypto,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +0530497 vif->grp_crypto_len, vif->ch_hint);
Kalle Valobdcd8172011-07-18 00:22:30 +0300498
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +0530499 vif->reconnect_flag = 0;
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530500 status = ath6kl_wmi_connect_cmd(ar->wmi, vif->fw_vif_idx, vif->nw_type,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530501 vif->dot11_auth_mode, vif->auth_mode,
502 vif->prwise_crypto,
503 vif->prwise_crypto_len,
504 vif->grp_crypto, vif->grp_crypto_len,
505 vif->ssid_len, vif->ssid,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +0530506 vif->req_bssid, vif->ch_hint,
Kalle Valobdcd8172011-07-18 00:22:30 +0300507 ar->connect_ctrl_flags);
508
509 up(&ar->sem);
510
511 if (status == -EINVAL) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530512 memset(vif->ssid, 0, sizeof(vif->ssid));
513 vif->ssid_len = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +0300514 ath6kl_err("invalid request\n");
515 return -ENOENT;
516 } else if (status) {
517 ath6kl_err("ath6kl_wmi_connect_cmd failed\n");
518 return -EIO;
519 }
520
521 if ((!(ar->connect_ctrl_flags & CONNECT_DO_WPA_OFFLOAD)) &&
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530522 ((vif->auth_mode == WPA_PSK_AUTH)
523 || (vif->auth_mode == WPA2_PSK_AUTH))) {
Vasanthakumar Thiagarajande3ad712011-10-25 19:34:08 +0530524 mod_timer(&vif->disconnect_timer,
Kalle Valobdcd8172011-07-18 00:22:30 +0300525 jiffies + msecs_to_jiffies(DISCON_TIMER_INTVAL));
526 }
527
528 ar->connect_ctrl_flags &= ~CONNECT_DO_WPA_OFFLOAD;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530529 set_bit(CONNECT_PEND, &vif->flags);
Kalle Valobdcd8172011-07-18 00:22:30 +0300530
531 return 0;
532}
533
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530534static int ath6kl_add_bss_if_needed(struct ath6kl_vif *vif, const u8 *bssid,
Jouni Malinen01cac472011-09-19 19:14:59 +0300535 struct ieee80211_channel *chan,
536 const u8 *beacon_ie, size_t beacon_ie_len)
537{
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530538 struct ath6kl *ar = vif->ar;
Jouni Malinen01cac472011-09-19 19:14:59 +0300539 struct cfg80211_bss *bss;
540 u8 *ie;
541
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +0530542 bss = cfg80211_get_bss(ar->wiphy, chan, bssid,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530543 vif->ssid, vif->ssid_len, WLAN_CAPABILITY_ESS,
Jouni Malinen01cac472011-09-19 19:14:59 +0300544 WLAN_CAPABILITY_ESS);
545 if (bss == NULL) {
546 /*
547 * Since cfg80211 may not yet know about the BSS,
548 * generate a partial entry until the first BSS info
549 * event becomes available.
550 *
551 * Prepend SSID element since it is not included in the Beacon
552 * IEs from the target.
553 */
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530554 ie = kmalloc(2 + vif->ssid_len + beacon_ie_len, GFP_KERNEL);
Jouni Malinen01cac472011-09-19 19:14:59 +0300555 if (ie == NULL)
556 return -ENOMEM;
557 ie[0] = WLAN_EID_SSID;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530558 ie[1] = vif->ssid_len;
559 memcpy(ie + 2, vif->ssid, vif->ssid_len);
560 memcpy(ie + 2 + vif->ssid_len, beacon_ie, beacon_ie_len);
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +0530561 bss = cfg80211_inform_bss(ar->wiphy, chan,
Jouni Malinen01cac472011-09-19 19:14:59 +0300562 bssid, 0, WLAN_CAPABILITY_ESS, 100,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530563 ie, 2 + vif->ssid_len + beacon_ie_len,
Jouni Malinen01cac472011-09-19 19:14:59 +0300564 0, GFP_KERNEL);
565 if (bss)
566 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "added dummy bss for "
567 "%pM prior to indicating connect/roamed "
568 "event\n", bssid);
569 kfree(ie);
570 } else
571 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "cfg80211 already has a bss "
572 "entry\n");
573
574 if (bss == NULL)
575 return -ENOMEM;
576
577 cfg80211_put_bss(bss);
578
579 return 0;
580}
581
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530582void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel,
Kalle Valobdcd8172011-07-18 00:22:30 +0300583 u8 *bssid, u16 listen_intvl,
584 u16 beacon_intvl,
585 enum network_type nw_type,
586 u8 beacon_ie_len, u8 assoc_req_len,
587 u8 assoc_resp_len, u8 *assoc_info)
588{
Jouni Malinen01cac472011-09-19 19:14:59 +0300589 struct ieee80211_channel *chan;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530590 struct ath6kl *ar = vif->ar;
Kalle Valobdcd8172011-07-18 00:22:30 +0300591
592 /* capinfo + listen interval */
593 u8 assoc_req_ie_offset = sizeof(u16) + sizeof(u16);
594
595 /* capinfo + status code + associd */
596 u8 assoc_resp_ie_offset = sizeof(u16) + sizeof(u16) + sizeof(u16);
597
598 u8 *assoc_req_ie = assoc_info + beacon_ie_len + assoc_req_ie_offset;
599 u8 *assoc_resp_ie = assoc_info + beacon_ie_len + assoc_req_len +
600 assoc_resp_ie_offset;
601
602 assoc_req_len -= assoc_req_ie_offset;
603 assoc_resp_len -= assoc_resp_ie_offset;
604
Jouni Malinen32c10872011-09-19 19:15:07 +0300605 /*
606 * Store Beacon interval here; DTIM period will be available only once
607 * a Beacon frame from the AP is seen.
608 */
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +0530609 vif->assoc_bss_beacon_int = beacon_intvl;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530610 clear_bit(DTIM_PERIOD_AVAIL, &vif->flags);
Jouni Malinen32c10872011-09-19 19:15:07 +0300611
Kalle Valobdcd8172011-07-18 00:22:30 +0300612 if (nw_type & ADHOC_NETWORK) {
613 if (ar->wdev->iftype != NL80211_IFTYPE_ADHOC) {
614 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
615 "%s: ath6k not in ibss mode\n", __func__);
616 return;
617 }
618 }
619
620 if (nw_type & INFRA_NETWORK) {
Jouni Malinen6b5e5d22011-08-30 21:58:05 +0300621 if (ar->wdev->iftype != NL80211_IFTYPE_STATION &&
622 ar->wdev->iftype != NL80211_IFTYPE_P2P_CLIENT) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300623 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
624 "%s: ath6k not in station mode\n", __func__);
625 return;
626 }
627 }
628
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +0530629 chan = ieee80211_get_channel(ar->wiphy, (int) channel);
Kalle Valobdcd8172011-07-18 00:22:30 +0300630
Kalle Valobdcd8172011-07-18 00:22:30 +0300631
632 if (nw_type & ADHOC_NETWORK) {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530633 cfg80211_ibss_joined(vif->ndev, bssid, GFP_KERNEL);
Kalle Valobdcd8172011-07-18 00:22:30 +0300634 return;
635 }
636
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530637 if (ath6kl_add_bss_if_needed(vif, bssid, chan, assoc_info,
Jouni Malinen01cac472011-09-19 19:14:59 +0300638 beacon_ie_len) < 0) {
639 ath6kl_err("could not add cfg80211 bss entry for "
640 "connect/roamed notification\n");
641 return;
642 }
643
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530644 if (vif->sme_state == SME_CONNECTING) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300645 /* inform connect result to cfg80211 */
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530646 vif->sme_state = SME_CONNECTED;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530647 cfg80211_connect_result(vif->ndev, bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +0300648 assoc_req_ie, assoc_req_len,
649 assoc_resp_ie, assoc_resp_len,
650 WLAN_STATUS_SUCCESS, GFP_KERNEL);
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530651 } else if (vif->sme_state == SME_CONNECTED) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300652 /* inform roam event to cfg80211 */
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530653 cfg80211_roamed(vif->ndev, chan, bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +0300654 assoc_req_ie, assoc_req_len,
655 assoc_resp_ie, assoc_resp_len, GFP_KERNEL);
656 }
657}
658
659static int ath6kl_cfg80211_disconnect(struct wiphy *wiphy,
660 struct net_device *dev, u16 reason_code)
661{
662 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(dev);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530663 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +0300664
665 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: reason=%u\n", __func__,
666 reason_code);
667
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530668 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +0300669 return -EIO;
670
671 if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) {
672 ath6kl_err("busy, destroy in progress\n");
673 return -EBUSY;
674 }
675
676 if (down_interruptible(&ar->sem)) {
677 ath6kl_err("busy, couldn't get access\n");
678 return -ERESTARTSYS;
679 }
680
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +0530681 vif->reconnect_flag = 0;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530682 ath6kl_disconnect(vif);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530683 memset(vif->ssid, 0, sizeof(vif->ssid));
684 vif->ssid_len = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +0300685
686 if (!test_bit(SKIP_SCAN, &ar->flag))
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +0530687 memset(vif->req_bssid, 0, sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +0300688
689 up(&ar->sem);
690
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530691 vif->sme_state = SME_DISCONNECTED;
Vasanthakumar Thiagarajan170826d2011-09-10 15:26:35 +0530692
Kalle Valobdcd8172011-07-18 00:22:30 +0300693 return 0;
694}
695
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530696void ath6kl_cfg80211_disconnect_event(struct ath6kl_vif *vif, u8 reason,
Kalle Valobdcd8172011-07-18 00:22:30 +0300697 u8 *bssid, u8 assoc_resp_len,
698 u8 *assoc_info, u16 proto_reason)
699{
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530700 struct ath6kl *ar = vif->ar;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530701
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530702 if (vif->scan_req) {
703 cfg80211_scan_done(vif->scan_req, true);
704 vif->scan_req = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +0300705 }
706
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +0530707 if (vif->nw_type & ADHOC_NETWORK) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300708 if (ar->wdev->iftype != NL80211_IFTYPE_ADHOC) {
709 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
710 "%s: ath6k not in ibss mode\n", __func__);
711 return;
712 }
713 memset(bssid, 0, ETH_ALEN);
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530714 cfg80211_ibss_joined(vif->ndev, bssid, GFP_KERNEL);
Kalle Valobdcd8172011-07-18 00:22:30 +0300715 return;
716 }
717
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +0530718 if (vif->nw_type & INFRA_NETWORK) {
Jouni Malinen6b5e5d22011-08-30 21:58:05 +0300719 if (ar->wdev->iftype != NL80211_IFTYPE_STATION &&
720 ar->wdev->iftype != NL80211_IFTYPE_P2P_CLIENT) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300721 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
722 "%s: ath6k not in station mode\n", __func__);
723 return;
724 }
725 }
726
Vasanthakumar Thiagarajan1de547d2011-09-23 10:57:50 +0530727 /*
728 * Send a disconnect command to target when a disconnect event is
729 * received with reason code other than 3 (DISCONNECT_CMD - disconnect
730 * request from host) to make the firmware stop trying to connect even
731 * after giving disconnect event. There will be one more disconnect
732 * event for this disconnect command with reason code DISCONNECT_CMD
733 * which will be notified to cfg80211.
734 */
Kalle Valobdcd8172011-07-18 00:22:30 +0300735
Vasanthakumar Thiagarajan1de547d2011-09-23 10:57:50 +0530736 if (reason != DISCONNECT_CMD) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530737 ath6kl_wmi_disconnect_cmd(ar->wmi, vif->fw_vif_idx);
Kalle Valobdcd8172011-07-18 00:22:30 +0300738 return;
739 }
740
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530741 clear_bit(CONNECT_PEND, &vif->flags);
Kalle Valobdcd8172011-07-18 00:22:30 +0300742
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530743 if (vif->sme_state == SME_CONNECTING) {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530744 cfg80211_connect_result(vif->ndev,
Vasanthakumar Thiagarajanac59a2b2011-09-10 15:26:34 +0530745 bssid, NULL, 0,
746 NULL, 0,
747 WLAN_STATUS_UNSPECIFIED_FAILURE,
748 GFP_KERNEL);
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530749 } else if (vif->sme_state == SME_CONNECTED) {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530750 cfg80211_disconnected(vif->ndev, reason,
Vasanthakumar Thiagarajanac59a2b2011-09-10 15:26:34 +0530751 NULL, 0, GFP_KERNEL);
Kalle Valobdcd8172011-07-18 00:22:30 +0300752 }
753
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530754 vif->sme_state = SME_DISCONNECTED;
Kalle Valobdcd8172011-07-18 00:22:30 +0300755}
756
Kalle Valobdcd8172011-07-18 00:22:30 +0300757static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
758 struct cfg80211_scan_request *request)
759{
760 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530761 struct ath6kl_vif *vif = netdev_priv(ndev);
Edward Lu1276c9e2011-08-30 21:58:00 +0300762 s8 n_channels = 0;
763 u16 *channels = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +0300764 int ret = 0;
Vasanthakumar Thiagarajanf1f92172011-10-01 16:12:36 +0530765 u32 force_fg_scan = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +0300766
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530767 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +0300768 return -EIO;
769
770 if (!ar->usr_bss_filter) {
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530771 clear_bit(CLEAR_BSSFILTER_ON_BEACON, &vif->flags);
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300772 ret = ath6kl_wmi_bssfilter_cmd(
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530773 ar->wmi, vif->fw_vif_idx,
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530774 (test_bit(CONNECTED, &vif->flags) ?
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300775 ALL_BUT_BSS_FILTER : ALL_BSS_FILTER), 0);
776 if (ret) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300777 ath6kl_err("couldn't set bss filtering\n");
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300778 return ret;
Kalle Valobdcd8172011-07-18 00:22:30 +0300779 }
780 }
781
782 if (request->n_ssids && request->ssids[0].ssid_len) {
783 u8 i;
784
785 if (request->n_ssids > (MAX_PROBED_SSID_INDEX - 1))
786 request->n_ssids = MAX_PROBED_SSID_INDEX - 1;
787
788 for (i = 0; i < request->n_ssids; i++)
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530789 ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx,
790 i + 1, SPECIFIC_SSID_FLAG,
Kalle Valobdcd8172011-07-18 00:22:30 +0300791 request->ssids[i].ssid_len,
792 request->ssids[i].ssid);
793 }
794
Jouni Malinenb84da8c2011-08-30 21:57:59 +0300795 if (request->ie) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530796 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
797 WMI_FRAME_PROBE_REQ,
Jouni Malinenb84da8c2011-08-30 21:57:59 +0300798 request->ie, request->ie_len);
799 if (ret) {
800 ath6kl_err("failed to set Probe Request appie for "
801 "scan");
802 return ret;
803 }
804 }
805
Jouni Malinen11869be2011-09-02 20:07:06 +0300806 /*
807 * Scan only the requested channels if the request specifies a set of
808 * channels. If the list is longer than the target supports, do not
809 * configure the list and instead, scan all available channels.
810 */
811 if (request->n_channels > 0 &&
812 request->n_channels <= WMI_MAX_CHANNELS) {
Edward Lu1276c9e2011-08-30 21:58:00 +0300813 u8 i;
814
Jouni Malinen11869be2011-09-02 20:07:06 +0300815 n_channels = request->n_channels;
Edward Lu1276c9e2011-08-30 21:58:00 +0300816
817 channels = kzalloc(n_channels * sizeof(u16), GFP_KERNEL);
818 if (channels == NULL) {
819 ath6kl_warn("failed to set scan channels, "
820 "scan all channels");
821 n_channels = 0;
822 }
823
824 for (i = 0; i < n_channels; i++)
825 channels[i] = request->channels[i]->center_freq;
826 }
827
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530828 if (test_bit(CONNECTED, &vif->flags))
Vasanthakumar Thiagarajanf1f92172011-10-01 16:12:36 +0530829 force_fg_scan = 1;
830
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530831 ret = ath6kl_wmi_startscan_cmd(ar->wmi, vif->fw_vif_idx, WMI_LONG_SCAN,
832 force_fg_scan, false, 0, 0, n_channels,
833 channels);
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300834 if (ret)
Kalle Valobdcd8172011-07-18 00:22:30 +0300835 ath6kl_err("wmi_startscan_cmd failed\n");
Jouni Malinen11869be2011-09-02 20:07:06 +0300836 else
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530837 vif->scan_req = request;
Kalle Valobdcd8172011-07-18 00:22:30 +0300838
Edward Lu1276c9e2011-08-30 21:58:00 +0300839 kfree(channels);
840
Kalle Valobdcd8172011-07-18 00:22:30 +0300841 return ret;
842}
843
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530844void ath6kl_cfg80211_scan_complete_event(struct ath6kl_vif *vif, int status)
Kalle Valobdcd8172011-07-18 00:22:30 +0300845{
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530846 struct ath6kl *ar = vif->ar;
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300847 int i;
Kalle Valobdcd8172011-07-18 00:22:30 +0300848
849 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: status %d\n", __func__, status);
850
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530851 if (!vif->scan_req)
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300852 return;
Kalle Valobdcd8172011-07-18 00:22:30 +0300853
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300854 if ((status == -ECANCELED) || (status == -EBUSY)) {
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530855 cfg80211_scan_done(vif->scan_req, true);
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300856 goto out;
Kalle Valobdcd8172011-07-18 00:22:30 +0300857 }
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300858
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530859 cfg80211_scan_done(vif->scan_req, false);
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300860
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530861 if (vif->scan_req->n_ssids && vif->scan_req->ssids[0].ssid_len) {
862 for (i = 0; i < vif->scan_req->n_ssids; i++) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530863 ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx,
864 i + 1, DISABLE_SSID_FLAG,
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300865 0, NULL);
866 }
867 }
868
869out:
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530870 vif->scan_req = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +0300871}
872
873static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
874 u8 key_index, bool pairwise,
875 const u8 *mac_addr,
876 struct key_params *params)
877{
878 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530879 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +0300880 struct ath6kl_key *key = NULL;
881 u8 key_usage;
882 u8 key_type;
883 int status = 0;
884
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530885 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +0300886 return -EIO;
887
Jouni Malinen837cb972011-10-11 17:31:57 +0300888 if (params->cipher == CCKM_KRK_CIPHER_SUITE) {
889 if (params->key_len != WMI_KRK_LEN)
890 return -EINVAL;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530891 return ath6kl_wmi_add_krk_cmd(ar->wmi, vif->fw_vif_idx,
892 params->key);
Jouni Malinen837cb972011-10-11 17:31:57 +0300893 }
894
Kalle Valobdcd8172011-07-18 00:22:30 +0300895 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
896 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
897 "%s: key index %d out of bounds\n", __func__,
898 key_index);
899 return -ENOENT;
900 }
901
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +0530902 key = &vif->keys[key_index];
Kalle Valobdcd8172011-07-18 00:22:30 +0300903 memset(key, 0, sizeof(struct ath6kl_key));
904
905 if (pairwise)
906 key_usage = PAIRWISE_USAGE;
907 else
908 key_usage = GROUP_USAGE;
909
910 if (params) {
911 if (params->key_len > WLAN_MAX_KEY_LEN ||
912 params->seq_len > sizeof(key->seq))
913 return -EINVAL;
914
915 key->key_len = params->key_len;
916 memcpy(key->key, params->key, key->key_len);
917 key->seq_len = params->seq_len;
918 memcpy(key->seq, params->seq, key->seq_len);
919 key->cipher = params->cipher;
920 }
921
922 switch (key->cipher) {
923 case WLAN_CIPHER_SUITE_WEP40:
924 case WLAN_CIPHER_SUITE_WEP104:
925 key_type = WEP_CRYPT;
926 break;
927
928 case WLAN_CIPHER_SUITE_TKIP:
929 key_type = TKIP_CRYPT;
930 break;
931
932 case WLAN_CIPHER_SUITE_CCMP:
933 key_type = AES_CRYPT;
934 break;
935
936 default:
937 return -ENOTSUPP;
938 }
939
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530940 if (((vif->auth_mode == WPA_PSK_AUTH)
941 || (vif->auth_mode == WPA2_PSK_AUTH))
Kalle Valobdcd8172011-07-18 00:22:30 +0300942 && (key_usage & GROUP_USAGE))
Vasanthakumar Thiagarajande3ad712011-10-25 19:34:08 +0530943 del_timer(&vif->disconnect_timer);
Kalle Valobdcd8172011-07-18 00:22:30 +0300944
945 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
946 "%s: index %d, key_len %d, key_type 0x%x, key_usage 0x%x, seq_len %d\n",
947 __func__, key_index, key->key_len, key_type,
948 key_usage, key->seq_len);
949
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530950 vif->def_txkey_index = key_index;
Jouni Malinen9a5b1312011-08-30 21:57:52 +0300951
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +0530952 if (vif->nw_type == AP_NETWORK && !pairwise &&
Jouni Malinen9a5b1312011-08-30 21:57:52 +0300953 (key_type == TKIP_CRYPT || key_type == AES_CRYPT) && params) {
954 ar->ap_mode_bkey.valid = true;
955 ar->ap_mode_bkey.key_index = key_index;
956 ar->ap_mode_bkey.key_type = key_type;
957 ar->ap_mode_bkey.key_len = key->key_len;
958 memcpy(ar->ap_mode_bkey.key, key->key, key->key_len);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530959 if (!test_bit(CONNECTED, &vif->flags)) {
Jouni Malinen9a5b1312011-08-30 21:57:52 +0300960 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delay initial group "
961 "key configuration until AP mode has been "
962 "started\n");
963 /*
964 * The key will be set in ath6kl_connect_ap_mode() once
965 * the connected event is received from the target.
966 */
967 return 0;
968 }
969 }
970
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +0530971 if (vif->next_mode == AP_NETWORK && key_type == WEP_CRYPT &&
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530972 !test_bit(CONNECTED, &vif->flags)) {
Jouni Malinen151411e2011-09-15 15:10:16 +0300973 /*
974 * Store the key locally so that it can be re-configured after
975 * the AP mode has properly started
976 * (ath6kl_install_statioc_wep_keys).
977 */
978 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delay WEP key configuration "
979 "until AP mode has been started\n");
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +0530980 vif->wep_key_list[key_index].key_len = key->key_len;
981 memcpy(vif->wep_key_list[key_index].key, key->key,
982 key->key_len);
Jouni Malinen151411e2011-09-15 15:10:16 +0300983 return 0;
984 }
985
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530986 status = ath6kl_wmi_addkey_cmd(ar->wmi, vif->fw_vif_idx,
987 vif->def_txkey_index,
Kalle Valobdcd8172011-07-18 00:22:30 +0300988 key_type, key_usage, key->key_len,
989 key->seq, key->key, KEY_OP_INIT_VAL,
990 (u8 *) mac_addr, SYNC_BOTH_WMIFLAG);
991
992 if (status)
993 return -EIO;
994
995 return 0;
996}
997
998static int ath6kl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
999 u8 key_index, bool pairwise,
1000 const u8 *mac_addr)
1001{
1002 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301003 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001004
1005 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
1006
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301007 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001008 return -EIO;
1009
1010 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
1011 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1012 "%s: key index %d out of bounds\n", __func__,
1013 key_index);
1014 return -ENOENT;
1015 }
1016
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301017 if (!vif->keys[key_index].key_len) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001018 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1019 "%s: index %d is empty\n", __func__, key_index);
1020 return 0;
1021 }
1022
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301023 vif->keys[key_index].key_len = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +03001024
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301025 return ath6kl_wmi_deletekey_cmd(ar->wmi, vif->fw_vif_idx, key_index);
Kalle Valobdcd8172011-07-18 00:22:30 +03001026}
1027
1028static int ath6kl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
1029 u8 key_index, bool pairwise,
1030 const u8 *mac_addr, void *cookie,
1031 void (*callback) (void *cookie,
1032 struct key_params *))
1033{
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301034 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001035 struct ath6kl_key *key = NULL;
1036 struct key_params params;
1037
1038 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
1039
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301040 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001041 return -EIO;
1042
1043 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
1044 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1045 "%s: key index %d out of bounds\n", __func__,
1046 key_index);
1047 return -ENOENT;
1048 }
1049
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301050 key = &vif->keys[key_index];
Kalle Valobdcd8172011-07-18 00:22:30 +03001051 memset(&params, 0, sizeof(params));
1052 params.cipher = key->cipher;
1053 params.key_len = key->key_len;
1054 params.seq_len = key->seq_len;
1055 params.seq = key->seq;
1056 params.key = key->key;
1057
1058 callback(cookie, &params);
1059
1060 return key->key_len ? 0 : -ENOENT;
1061}
1062
1063static int ath6kl_cfg80211_set_default_key(struct wiphy *wiphy,
1064 struct net_device *ndev,
1065 u8 key_index, bool unicast,
1066 bool multicast)
1067{
1068 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301069 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001070 struct ath6kl_key *key = NULL;
1071 int status = 0;
1072 u8 key_usage;
Edward Lu229ed6b2011-08-30 21:58:07 +03001073 enum crypto_type key_type = NONE_CRYPT;
Kalle Valobdcd8172011-07-18 00:22:30 +03001074
1075 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
1076
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301077 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001078 return -EIO;
1079
1080 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
1081 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1082 "%s: key index %d out of bounds\n",
1083 __func__, key_index);
1084 return -ENOENT;
1085 }
1086
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301087 if (!vif->keys[key_index].key_len) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001088 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: invalid key index %d\n",
1089 __func__, key_index);
1090 return -EINVAL;
1091 }
1092
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301093 vif->def_txkey_index = key_index;
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301094 key = &vif->keys[vif->def_txkey_index];
Kalle Valobdcd8172011-07-18 00:22:30 +03001095 key_usage = GROUP_USAGE;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301096 if (vif->prwise_crypto == WEP_CRYPT)
Kalle Valobdcd8172011-07-18 00:22:30 +03001097 key_usage |= TX_USAGE;
Edward Lu229ed6b2011-08-30 21:58:07 +03001098 if (unicast)
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301099 key_type = vif->prwise_crypto;
Edward Lu229ed6b2011-08-30 21:58:07 +03001100 if (multicast)
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301101 key_type = vif->grp_crypto;
Kalle Valobdcd8172011-07-18 00:22:30 +03001102
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301103 if (vif->next_mode == AP_NETWORK && !test_bit(CONNECTED, &vif->flags))
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001104 return 0; /* Delay until AP mode has been started */
1105
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301106 status = ath6kl_wmi_addkey_cmd(ar->wmi, vif->fw_vif_idx,
1107 vif->def_txkey_index,
Edward Lu229ed6b2011-08-30 21:58:07 +03001108 key_type, key_usage,
Kalle Valobdcd8172011-07-18 00:22:30 +03001109 key->key_len, key->seq, key->key,
1110 KEY_OP_INIT_VAL, NULL,
1111 SYNC_BOTH_WMIFLAG);
1112 if (status)
1113 return -EIO;
1114
1115 return 0;
1116}
1117
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301118void ath6kl_cfg80211_tkip_micerr_event(struct ath6kl_vif *vif, u8 keyid,
Kalle Valobdcd8172011-07-18 00:22:30 +03001119 bool ismcast)
1120{
1121 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1122 "%s: keyid %d, ismcast %d\n", __func__, keyid, ismcast);
1123
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301124 cfg80211_michael_mic_failure(vif->ndev, vif->bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +03001125 (ismcast ? NL80211_KEYTYPE_GROUP :
1126 NL80211_KEYTYPE_PAIRWISE), keyid, NULL,
1127 GFP_KERNEL);
1128}
1129
1130static int ath6kl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
1131{
1132 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301133 struct ath6kl_vif *vif;
Kalle Valobdcd8172011-07-18 00:22:30 +03001134 int ret;
1135
1136 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: changed 0x%x\n", __func__,
1137 changed);
1138
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301139 vif = ath6kl_vif_first(ar);
1140 if (!vif)
1141 return -EIO;
1142
1143 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001144 return -EIO;
1145
1146 if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
1147 ret = ath6kl_wmi_set_rts_cmd(ar->wmi, wiphy->rts_threshold);
1148 if (ret != 0) {
1149 ath6kl_err("ath6kl_wmi_set_rts_cmd failed\n");
1150 return -EIO;
1151 }
1152 }
1153
1154 return 0;
1155}
1156
1157/*
1158 * The type nl80211_tx_power_setting replaces the following
1159 * data type from 2.6.36 onwards
1160*/
1161static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy,
1162 enum nl80211_tx_power_setting type,
1163 int dbm)
1164{
1165 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301166 struct ath6kl_vif *vif;
Kalle Valobdcd8172011-07-18 00:22:30 +03001167 u8 ath6kl_dbm;
1168
1169 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x, dbm %d\n", __func__,
1170 type, dbm);
1171
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301172 vif = ath6kl_vif_first(ar);
1173 if (!vif)
1174 return -EIO;
1175
1176 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001177 return -EIO;
1178
1179 switch (type) {
1180 case NL80211_TX_POWER_AUTOMATIC:
1181 return 0;
1182 case NL80211_TX_POWER_LIMITED:
1183 ar->tx_pwr = ath6kl_dbm = dbm;
1184 break;
1185 default:
1186 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x not supported\n",
1187 __func__, type);
1188 return -EOPNOTSUPP;
1189 }
1190
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301191 ath6kl_wmi_set_tx_pwr_cmd(ar->wmi, vif->fw_vif_idx, ath6kl_dbm);
Kalle Valobdcd8172011-07-18 00:22:30 +03001192
1193 return 0;
1194}
1195
1196static int ath6kl_cfg80211_get_txpower(struct wiphy *wiphy, int *dbm)
1197{
1198 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301199 struct ath6kl_vif *vif;
Kalle Valobdcd8172011-07-18 00:22:30 +03001200
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301201 vif = ath6kl_vif_first(ar);
1202 if (!vif)
1203 return -EIO;
1204
1205 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001206 return -EIO;
1207
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301208 if (test_bit(CONNECTED, &vif->flags)) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001209 ar->tx_pwr = 0;
1210
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301211 if (ath6kl_wmi_get_tx_pwr_cmd(ar->wmi, vif->fw_vif_idx) != 0) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001212 ath6kl_err("ath6kl_wmi_get_tx_pwr_cmd failed\n");
1213 return -EIO;
1214 }
1215
1216 wait_event_interruptible_timeout(ar->event_wq, ar->tx_pwr != 0,
1217 5 * HZ);
1218
1219 if (signal_pending(current)) {
1220 ath6kl_err("target did not respond\n");
1221 return -EINTR;
1222 }
1223 }
1224
1225 *dbm = ar->tx_pwr;
1226 return 0;
1227}
1228
1229static int ath6kl_cfg80211_set_power_mgmt(struct wiphy *wiphy,
1230 struct net_device *dev,
1231 bool pmgmt, int timeout)
1232{
1233 struct ath6kl *ar = ath6kl_priv(dev);
1234 struct wmi_power_mode_cmd mode;
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301235 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001236
1237 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: pmgmt %d, timeout %d\n",
1238 __func__, pmgmt, timeout);
1239
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301240 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001241 return -EIO;
1242
1243 if (pmgmt) {
1244 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: max perf\n", __func__);
1245 mode.pwr_mode = REC_POWER;
1246 } else {
1247 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: rec power\n", __func__);
1248 mode.pwr_mode = MAX_PERF_POWER;
1249 }
1250
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301251 if (ath6kl_wmi_powermode_cmd(ar->wmi, vif->fw_vif_idx,
1252 mode.pwr_mode) != 0) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001253 ath6kl_err("wmi_powermode_cmd failed\n");
1254 return -EIO;
1255 }
1256
1257 return 0;
1258}
1259
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05301260static struct net_device *ath6kl_cfg80211_add_iface(struct wiphy *wiphy,
1261 char *name,
1262 enum nl80211_iftype type,
1263 u32 *flags,
1264 struct vif_params *params)
1265{
1266 struct ath6kl *ar = wiphy_priv(wiphy);
1267 struct net_device *ndev;
1268 u8 if_idx, nw_type;
1269
1270 if (ar->num_vif == MAX_NUM_VIF) {
1271 ath6kl_err("Reached maximum number of supported vif\n");
1272 return ERR_PTR(-EINVAL);
1273 }
1274
1275 if (!ath6kl_is_valid_iftype(ar, type, &if_idx, &nw_type)) {
1276 ath6kl_err("Not a supported interface type\n");
1277 return ERR_PTR(-EINVAL);
1278 }
1279
1280 ndev = ath6kl_interface_add(ar, name, type, if_idx, nw_type);
1281 if (!ndev)
1282 return ERR_PTR(-ENOMEM);
1283
1284 ar->num_vif++;
1285
1286 return ndev;
1287}
1288
1289static int ath6kl_cfg80211_del_iface(struct wiphy *wiphy,
1290 struct net_device *ndev)
1291{
1292 struct ath6kl *ar = wiphy_priv(wiphy);
1293 struct ath6kl_vif *vif = netdev_priv(ndev);
1294
1295 spin_lock(&ar->list_lock);
1296 list_del(&vif->list);
1297 spin_unlock(&ar->list_lock);
1298
1299 ath6kl_cleanup_vif(vif, test_bit(WMI_READY, &ar->flag));
1300
1301 ath6kl_deinit_if_data(vif);
1302
1303 return 0;
1304}
1305
Kalle Valobdcd8172011-07-18 00:22:30 +03001306static int ath6kl_cfg80211_change_iface(struct wiphy *wiphy,
1307 struct net_device *ndev,
1308 enum nl80211_iftype type, u32 *flags,
1309 struct vif_params *params)
1310{
1311 struct ath6kl *ar = ath6kl_priv(ndev);
1312 struct wireless_dev *wdev = ar->wdev;
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301313 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001314
1315 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type %u\n", __func__, type);
1316
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301317 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001318 return -EIO;
1319
1320 switch (type) {
1321 case NL80211_IFTYPE_STATION:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301322 vif->next_mode = INFRA_NETWORK;
Kalle Valobdcd8172011-07-18 00:22:30 +03001323 break;
1324 case NL80211_IFTYPE_ADHOC:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301325 vif->next_mode = ADHOC_NETWORK;
Kalle Valobdcd8172011-07-18 00:22:30 +03001326 break;
Jouni Malinen6e4604c2011-09-05 17:38:46 +03001327 case NL80211_IFTYPE_AP:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301328 vif->next_mode = AP_NETWORK;
Jouni Malinen6e4604c2011-09-05 17:38:46 +03001329 break;
Jouni Malinen6b5e5d22011-08-30 21:58:05 +03001330 case NL80211_IFTYPE_P2P_CLIENT:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301331 vif->next_mode = INFRA_NETWORK;
Jouni Malinen6b5e5d22011-08-30 21:58:05 +03001332 break;
1333 case NL80211_IFTYPE_P2P_GO:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301334 vif->next_mode = AP_NETWORK;
Jouni Malinen6b5e5d22011-08-30 21:58:05 +03001335 break;
Kalle Valobdcd8172011-07-18 00:22:30 +03001336 default:
1337 ath6kl_err("invalid interface type %u\n", type);
1338 return -EOPNOTSUPP;
1339 }
1340
1341 wdev->iftype = type;
1342
1343 return 0;
1344}
1345
1346static int ath6kl_cfg80211_join_ibss(struct wiphy *wiphy,
1347 struct net_device *dev,
1348 struct cfg80211_ibss_params *ibss_param)
1349{
1350 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301351 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001352 int status;
1353
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301354 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001355 return -EIO;
1356
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301357 vif->ssid_len = ibss_param->ssid_len;
1358 memcpy(vif->ssid, ibss_param->ssid, vif->ssid_len);
Kalle Valobdcd8172011-07-18 00:22:30 +03001359
1360 if (ibss_param->channel)
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +05301361 vif->ch_hint = ibss_param->channel->center_freq;
Kalle Valobdcd8172011-07-18 00:22:30 +03001362
1363 if (ibss_param->channel_fixed) {
1364 /*
1365 * TODO: channel_fixed: The channel should be fixed, do not
1366 * search for IBSSs to join on other channels. Target
1367 * firmware does not support this feature, needs to be
1368 * updated.
1369 */
1370 return -EOPNOTSUPP;
1371 }
1372
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +05301373 memset(vif->req_bssid, 0, sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +03001374 if (ibss_param->bssid && !is_broadcast_ether_addr(ibss_param->bssid))
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +05301375 memcpy(vif->req_bssid, ibss_param->bssid,
1376 sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +03001377
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301378 ath6kl_set_wpa_version(vif, 0);
Kalle Valobdcd8172011-07-18 00:22:30 +03001379
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301380 status = ath6kl_set_auth_type(vif, NL80211_AUTHTYPE_OPEN_SYSTEM);
Kalle Valobdcd8172011-07-18 00:22:30 +03001381 if (status)
1382 return status;
1383
1384 if (ibss_param->privacy) {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301385 ath6kl_set_cipher(vif, WLAN_CIPHER_SUITE_WEP40, true);
1386 ath6kl_set_cipher(vif, WLAN_CIPHER_SUITE_WEP40, false);
Kalle Valobdcd8172011-07-18 00:22:30 +03001387 } else {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301388 ath6kl_set_cipher(vif, 0, true);
1389 ath6kl_set_cipher(vif, 0, false);
Kalle Valobdcd8172011-07-18 00:22:30 +03001390 }
1391
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301392 vif->nw_type = vif->next_mode;
Kalle Valobdcd8172011-07-18 00:22:30 +03001393
1394 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1395 "%s: connect called with authmode %d dot11 auth %d"
1396 " PW crypto %d PW crypto len %d GRP crypto %d"
1397 " GRP crypto len %d channel hint %u\n",
1398 __func__,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301399 vif->auth_mode, vif->dot11_auth_mode, vif->prwise_crypto,
1400 vif->prwise_crypto_len, vif->grp_crypto,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +05301401 vif->grp_crypto_len, vif->ch_hint);
Kalle Valobdcd8172011-07-18 00:22:30 +03001402
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301403 status = ath6kl_wmi_connect_cmd(ar->wmi, vif->fw_vif_idx, vif->nw_type,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301404 vif->dot11_auth_mode, vif->auth_mode,
1405 vif->prwise_crypto,
1406 vif->prwise_crypto_len,
1407 vif->grp_crypto, vif->grp_crypto_len,
1408 vif->ssid_len, vif->ssid,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +05301409 vif->req_bssid, vif->ch_hint,
Kalle Valobdcd8172011-07-18 00:22:30 +03001410 ar->connect_ctrl_flags);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301411 set_bit(CONNECT_PEND, &vif->flags);
Kalle Valobdcd8172011-07-18 00:22:30 +03001412
1413 return 0;
1414}
1415
1416static int ath6kl_cfg80211_leave_ibss(struct wiphy *wiphy,
1417 struct net_device *dev)
1418{
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301419 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001420
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301421 if (!ath6kl_cfg80211_ready(vif))
Kalle Valobdcd8172011-07-18 00:22:30 +03001422 return -EIO;
1423
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301424 ath6kl_disconnect(vif);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301425 memset(vif->ssid, 0, sizeof(vif->ssid));
1426 vif->ssid_len = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +03001427
1428 return 0;
1429}
1430
1431static const u32 cipher_suites[] = {
1432 WLAN_CIPHER_SUITE_WEP40,
1433 WLAN_CIPHER_SUITE_WEP104,
1434 WLAN_CIPHER_SUITE_TKIP,
1435 WLAN_CIPHER_SUITE_CCMP,
Jouni Malinen837cb972011-10-11 17:31:57 +03001436 CCKM_KRK_CIPHER_SUITE,
Kalle Valobdcd8172011-07-18 00:22:30 +03001437};
1438
1439static bool is_rate_legacy(s32 rate)
1440{
1441 static const s32 legacy[] = { 1000, 2000, 5500, 11000,
1442 6000, 9000, 12000, 18000, 24000,
1443 36000, 48000, 54000
1444 };
1445 u8 i;
1446
1447 for (i = 0; i < ARRAY_SIZE(legacy); i++)
1448 if (rate == legacy[i])
1449 return true;
1450
1451 return false;
1452}
1453
1454static bool is_rate_ht20(s32 rate, u8 *mcs, bool *sgi)
1455{
1456 static const s32 ht20[] = { 6500, 13000, 19500, 26000, 39000,
1457 52000, 58500, 65000, 72200
1458 };
1459 u8 i;
1460
1461 for (i = 0; i < ARRAY_SIZE(ht20); i++) {
1462 if (rate == ht20[i]) {
1463 if (i == ARRAY_SIZE(ht20) - 1)
1464 /* last rate uses sgi */
1465 *sgi = true;
1466 else
1467 *sgi = false;
1468
1469 *mcs = i;
1470 return true;
1471 }
1472 }
1473 return false;
1474}
1475
1476static bool is_rate_ht40(s32 rate, u8 *mcs, bool *sgi)
1477{
1478 static const s32 ht40[] = { 13500, 27000, 40500, 54000,
1479 81000, 108000, 121500, 135000,
1480 150000
1481 };
1482 u8 i;
1483
1484 for (i = 0; i < ARRAY_SIZE(ht40); i++) {
1485 if (rate == ht40[i]) {
1486 if (i == ARRAY_SIZE(ht40) - 1)
1487 /* last rate uses sgi */
1488 *sgi = true;
1489 else
1490 *sgi = false;
1491
1492 *mcs = i;
1493 return true;
1494 }
1495 }
1496
1497 return false;
1498}
1499
1500static int ath6kl_get_station(struct wiphy *wiphy, struct net_device *dev,
1501 u8 *mac, struct station_info *sinfo)
1502{
1503 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301504 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001505 long left;
1506 bool sgi;
1507 s32 rate;
1508 int ret;
1509 u8 mcs;
1510
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +05301511 if (memcmp(mac, vif->bssid, ETH_ALEN) != 0)
Kalle Valobdcd8172011-07-18 00:22:30 +03001512 return -ENOENT;
1513
1514 if (down_interruptible(&ar->sem))
1515 return -EBUSY;
1516
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301517 set_bit(STATS_UPDATE_PEND, &vif->flags);
Kalle Valobdcd8172011-07-18 00:22:30 +03001518
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301519 ret = ath6kl_wmi_get_stats_cmd(ar->wmi, vif->fw_vif_idx);
Kalle Valobdcd8172011-07-18 00:22:30 +03001520
1521 if (ret != 0) {
1522 up(&ar->sem);
1523 return -EIO;
1524 }
1525
1526 left = wait_event_interruptible_timeout(ar->event_wq,
1527 !test_bit(STATS_UPDATE_PEND,
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301528 &vif->flags),
Kalle Valobdcd8172011-07-18 00:22:30 +03001529 WMI_TIMEOUT);
1530
1531 up(&ar->sem);
1532
1533 if (left == 0)
1534 return -ETIMEDOUT;
1535 else if (left < 0)
1536 return left;
1537
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301538 if (vif->target_stats.rx_byte) {
1539 sinfo->rx_bytes = vif->target_stats.rx_byte;
Kalle Valobdcd8172011-07-18 00:22:30 +03001540 sinfo->filled |= STATION_INFO_RX_BYTES;
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301541 sinfo->rx_packets = vif->target_stats.rx_pkt;
Kalle Valobdcd8172011-07-18 00:22:30 +03001542 sinfo->filled |= STATION_INFO_RX_PACKETS;
1543 }
1544
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301545 if (vif->target_stats.tx_byte) {
1546 sinfo->tx_bytes = vif->target_stats.tx_byte;
Kalle Valobdcd8172011-07-18 00:22:30 +03001547 sinfo->filled |= STATION_INFO_TX_BYTES;
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301548 sinfo->tx_packets = vif->target_stats.tx_pkt;
Kalle Valobdcd8172011-07-18 00:22:30 +03001549 sinfo->filled |= STATION_INFO_TX_PACKETS;
1550 }
1551
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301552 sinfo->signal = vif->target_stats.cs_rssi;
Kalle Valobdcd8172011-07-18 00:22:30 +03001553 sinfo->filled |= STATION_INFO_SIGNAL;
1554
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301555 rate = vif->target_stats.tx_ucast_rate;
Kalle Valobdcd8172011-07-18 00:22:30 +03001556
1557 if (is_rate_legacy(rate)) {
1558 sinfo->txrate.legacy = rate / 100;
1559 } else if (is_rate_ht20(rate, &mcs, &sgi)) {
1560 if (sgi) {
1561 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
1562 sinfo->txrate.mcs = mcs - 1;
1563 } else {
1564 sinfo->txrate.mcs = mcs;
1565 }
1566
1567 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
1568 } else if (is_rate_ht40(rate, &mcs, &sgi)) {
1569 if (sgi) {
1570 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
1571 sinfo->txrate.mcs = mcs - 1;
1572 } else {
1573 sinfo->txrate.mcs = mcs;
1574 }
1575
1576 sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
1577 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
1578 } else {
Kalle Valo9a730832011-09-27 23:33:28 +03001579 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1580 "invalid rate from stats: %d\n", rate);
1581 ath6kl_debug_war(ar, ATH6KL_WAR_INVALID_RATE);
Kalle Valobdcd8172011-07-18 00:22:30 +03001582 return 0;
1583 }
1584
1585 sinfo->filled |= STATION_INFO_TX_BITRATE;
1586
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301587 if (test_bit(CONNECTED, &vif->flags) &&
1588 test_bit(DTIM_PERIOD_AVAIL, &vif->flags) &&
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301589 vif->nw_type == INFRA_NETWORK) {
Jouni Malinen32c10872011-09-19 19:15:07 +03001590 sinfo->filled |= STATION_INFO_BSS_PARAM;
1591 sinfo->bss_param.flags = 0;
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05301592 sinfo->bss_param.dtim_period = vif->assoc_bss_dtim_period;
1593 sinfo->bss_param.beacon_interval = vif->assoc_bss_beacon_int;
Jouni Malinen32c10872011-09-19 19:15:07 +03001594 }
1595
Kalle Valobdcd8172011-07-18 00:22:30 +03001596 return 0;
1597}
1598
1599static int ath6kl_set_pmksa(struct wiphy *wiphy, struct net_device *netdev,
1600 struct cfg80211_pmksa *pmksa)
1601{
1602 struct ath6kl *ar = ath6kl_priv(netdev);
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301603 struct ath6kl_vif *vif = netdev_priv(netdev);
1604
1605 return ath6kl_wmi_setpmkid_cmd(ar->wmi, vif->fw_vif_idx, pmksa->bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +03001606 pmksa->pmkid, true);
1607}
1608
1609static int ath6kl_del_pmksa(struct wiphy *wiphy, struct net_device *netdev,
1610 struct cfg80211_pmksa *pmksa)
1611{
1612 struct ath6kl *ar = ath6kl_priv(netdev);
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301613 struct ath6kl_vif *vif = netdev_priv(netdev);
1614
1615 return ath6kl_wmi_setpmkid_cmd(ar->wmi, vif->fw_vif_idx, pmksa->bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +03001616 pmksa->pmkid, false);
1617}
1618
1619static int ath6kl_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev)
1620{
1621 struct ath6kl *ar = ath6kl_priv(netdev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301622 struct ath6kl_vif *vif = netdev_priv(netdev);
1623
1624 if (test_bit(CONNECTED, &vif->flags))
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301625 return ath6kl_wmi_setpmkid_cmd(ar->wmi, vif->fw_vif_idx,
1626 vif->bssid, NULL, false);
Kalle Valobdcd8172011-07-18 00:22:30 +03001627 return 0;
1628}
1629
Kalle Valoabcb3442011-07-22 08:26:20 +03001630#ifdef CONFIG_PM
1631static int ar6k_cfg80211_suspend(struct wiphy *wiphy,
1632 struct cfg80211_wowlan *wow)
1633{
1634 struct ath6kl *ar = wiphy_priv(wiphy);
1635
1636 return ath6kl_hif_suspend(ar);
1637}
Chilam Ngaa6cffc2011-10-05 10:12:52 +03001638
1639static int ar6k_cfg80211_resume(struct wiphy *wiphy)
1640{
1641 struct ath6kl *ar = wiphy_priv(wiphy);
1642
1643 return ath6kl_hif_resume(ar);
1644}
Kalle Valoabcb3442011-07-22 08:26:20 +03001645#endif
1646
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001647static int ath6kl_set_channel(struct wiphy *wiphy, struct net_device *dev,
1648 struct ieee80211_channel *chan,
1649 enum nl80211_channel_type channel_type)
1650{
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05301651 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001652
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301653 if (!ath6kl_cfg80211_ready(vif))
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001654 return -EIO;
1655
1656 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: center_freq=%u hw_value=%u\n",
1657 __func__, chan->center_freq, chan->hw_value);
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05301658 vif->next_chan = chan->center_freq;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001659
1660 return 0;
1661}
1662
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001663static bool ath6kl_is_p2p_ie(const u8 *pos)
1664{
1665 return pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
1666 pos[2] == 0x50 && pos[3] == 0x6f &&
1667 pos[4] == 0x9a && pos[5] == 0x09;
1668}
1669
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301670static int ath6kl_set_ap_probe_resp_ies(struct ath6kl_vif *vif,
1671 const u8 *ies, size_t ies_len)
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001672{
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301673 struct ath6kl *ar = vif->ar;
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001674 const u8 *pos;
1675 u8 *buf = NULL;
1676 size_t len = 0;
1677 int ret;
1678
1679 /*
1680 * Filter out P2P IE(s) since they will be included depending on
1681 * the Probe Request frame in ath6kl_send_go_probe_resp().
1682 */
1683
1684 if (ies && ies_len) {
1685 buf = kmalloc(ies_len, GFP_KERNEL);
1686 if (buf == NULL)
1687 return -ENOMEM;
1688 pos = ies;
1689 while (pos + 1 < ies + ies_len) {
1690 if (pos + 2 + pos[1] > ies + ies_len)
1691 break;
1692 if (!ath6kl_is_p2p_ie(pos)) {
1693 memcpy(buf + len, pos, 2 + pos[1]);
1694 len += 2 + pos[1];
1695 }
1696 pos += 2 + pos[1];
1697 }
1698 }
1699
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301700 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
1701 WMI_FRAME_PROBE_RESP, buf, len);
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001702 kfree(buf);
1703 return ret;
1704}
1705
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001706static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
1707 struct beacon_parameters *info, bool add)
1708{
1709 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301710 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001711 struct ieee80211_mgmt *mgmt;
1712 u8 *ies;
1713 int ies_len;
1714 struct wmi_connect_cmd p;
1715 int res;
1716 int i;
1717
1718 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: add=%d\n", __func__, add);
1719
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301720 if (!ath6kl_cfg80211_ready(vif))
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001721 return -EIO;
1722
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301723 if (vif->next_mode != AP_NETWORK)
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001724 return -EOPNOTSUPP;
1725
1726 if (info->beacon_ies) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301727 res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
1728 WMI_FRAME_BEACON,
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001729 info->beacon_ies,
1730 info->beacon_ies_len);
1731 if (res)
1732 return res;
1733 }
1734 if (info->proberesp_ies) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301735 res = ath6kl_set_ap_probe_resp_ies(vif, info->proberesp_ies,
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001736 info->proberesp_ies_len);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001737 if (res)
1738 return res;
1739 }
1740 if (info->assocresp_ies) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301741 res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
1742 WMI_FRAME_ASSOC_RESP,
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001743 info->assocresp_ies,
1744 info->assocresp_ies_len);
1745 if (res)
1746 return res;
1747 }
1748
1749 if (!add)
1750 return 0;
1751
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001752 ar->ap_mode_bkey.valid = false;
1753
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001754 /* TODO:
1755 * info->interval
1756 * info->dtim_period
1757 */
1758
1759 if (info->head == NULL)
1760 return -EINVAL;
1761 mgmt = (struct ieee80211_mgmt *) info->head;
1762 ies = mgmt->u.beacon.variable;
1763 if (ies > info->head + info->head_len)
1764 return -EINVAL;
1765 ies_len = info->head + info->head_len - ies;
1766
1767 if (info->ssid == NULL)
1768 return -EINVAL;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301769 memcpy(vif->ssid, info->ssid, info->ssid_len);
1770 vif->ssid_len = info->ssid_len;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001771 if (info->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE)
1772 return -EOPNOTSUPP; /* TODO */
1773
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301774 vif->dot11_auth_mode = OPEN_AUTH;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001775
1776 memset(&p, 0, sizeof(p));
1777
1778 for (i = 0; i < info->crypto.n_akm_suites; i++) {
1779 switch (info->crypto.akm_suites[i]) {
1780 case WLAN_AKM_SUITE_8021X:
1781 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_1)
1782 p.auth_mode |= WPA_AUTH;
1783 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_2)
1784 p.auth_mode |= WPA2_AUTH;
1785 break;
1786 case WLAN_AKM_SUITE_PSK:
1787 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_1)
1788 p.auth_mode |= WPA_PSK_AUTH;
1789 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_2)
1790 p.auth_mode |= WPA2_PSK_AUTH;
1791 break;
1792 }
1793 }
1794 if (p.auth_mode == 0)
1795 p.auth_mode = NONE_AUTH;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301796 vif->auth_mode = p.auth_mode;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001797
1798 for (i = 0; i < info->crypto.n_ciphers_pairwise; i++) {
1799 switch (info->crypto.ciphers_pairwise[i]) {
1800 case WLAN_CIPHER_SUITE_WEP40:
1801 case WLAN_CIPHER_SUITE_WEP104:
1802 p.prwise_crypto_type |= WEP_CRYPT;
1803 break;
1804 case WLAN_CIPHER_SUITE_TKIP:
1805 p.prwise_crypto_type |= TKIP_CRYPT;
1806 break;
1807 case WLAN_CIPHER_SUITE_CCMP:
1808 p.prwise_crypto_type |= AES_CRYPT;
1809 break;
1810 }
1811 }
Edward Lu229ed6b2011-08-30 21:58:07 +03001812 if (p.prwise_crypto_type == 0) {
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001813 p.prwise_crypto_type = NONE_CRYPT;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301814 ath6kl_set_cipher(vif, 0, true);
Edward Lu229ed6b2011-08-30 21:58:07 +03001815 } else if (info->crypto.n_ciphers_pairwise == 1)
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301816 ath6kl_set_cipher(vif, info->crypto.ciphers_pairwise[0], true);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001817
1818 switch (info->crypto.cipher_group) {
1819 case WLAN_CIPHER_SUITE_WEP40:
1820 case WLAN_CIPHER_SUITE_WEP104:
1821 p.grp_crypto_type = WEP_CRYPT;
1822 break;
1823 case WLAN_CIPHER_SUITE_TKIP:
1824 p.grp_crypto_type = TKIP_CRYPT;
1825 break;
1826 case WLAN_CIPHER_SUITE_CCMP:
1827 p.grp_crypto_type = AES_CRYPT;
1828 break;
1829 default:
1830 p.grp_crypto_type = NONE_CRYPT;
1831 break;
1832 }
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301833 ath6kl_set_cipher(vif, info->crypto.cipher_group, false);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001834
1835 p.nw_type = AP_NETWORK;
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301836 vif->nw_type = vif->next_mode;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001837
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301838 p.ssid_len = vif->ssid_len;
1839 memcpy(p.ssid, vif->ssid, vif->ssid_len);
1840 p.dot11_auth_mode = vif->dot11_auth_mode;
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05301841 p.ch = cpu_to_le16(vif->next_chan);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001842
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301843 res = ath6kl_wmi_ap_profile_commit(ar->wmi, vif->fw_vif_idx, &p);
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001844 if (res < 0)
1845 return res;
1846
1847 return 0;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001848}
1849
1850static int ath6kl_add_beacon(struct wiphy *wiphy, struct net_device *dev,
1851 struct beacon_parameters *info)
1852{
1853 return ath6kl_ap_beacon(wiphy, dev, info, true);
1854}
1855
1856static int ath6kl_set_beacon(struct wiphy *wiphy, struct net_device *dev,
1857 struct beacon_parameters *info)
1858{
1859 return ath6kl_ap_beacon(wiphy, dev, info, false);
1860}
1861
1862static int ath6kl_del_beacon(struct wiphy *wiphy, struct net_device *dev)
1863{
1864 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301865 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001866
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301867 if (vif->nw_type != AP_NETWORK)
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001868 return -EOPNOTSUPP;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301869 if (!test_bit(CONNECTED, &vif->flags))
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001870 return -ENOTCONN;
1871
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301872 ath6kl_wmi_disconnect_cmd(ar->wmi, vif->fw_vif_idx);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301873 clear_bit(CONNECTED, &vif->flags);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001874
1875 return 0;
1876}
1877
Jouni Malinen23875132011-08-30 21:57:53 +03001878static int ath6kl_change_station(struct wiphy *wiphy, struct net_device *dev,
1879 u8 *mac, struct station_parameters *params)
1880{
1881 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301882 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen23875132011-08-30 21:57:53 +03001883
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301884 if (vif->nw_type != AP_NETWORK)
Jouni Malinen23875132011-08-30 21:57:53 +03001885 return -EOPNOTSUPP;
1886
1887 /* Use this only for authorizing/unauthorizing a station */
1888 if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)))
1889 return -EOPNOTSUPP;
1890
1891 if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED))
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301892 return ath6kl_wmi_ap_set_mlme(ar->wmi, vif->fw_vif_idx,
1893 WMI_AP_MLME_AUTHORIZE, mac, 0);
1894 return ath6kl_wmi_ap_set_mlme(ar->wmi, vif->fw_vif_idx,
1895 WMI_AP_MLME_UNAUTHORIZE, mac, 0);
Jouni Malinen23875132011-08-30 21:57:53 +03001896}
1897
Jouni Malinen63fa1e02011-08-30 21:57:55 +03001898static int ath6kl_remain_on_channel(struct wiphy *wiphy,
1899 struct net_device *dev,
1900 struct ieee80211_channel *chan,
1901 enum nl80211_channel_type channel_type,
1902 unsigned int duration,
1903 u64 *cookie)
1904{
1905 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301906 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen63fa1e02011-08-30 21:57:55 +03001907
1908 /* TODO: if already pending or ongoing remain-on-channel,
1909 * return -EBUSY */
1910 *cookie = 1; /* only a single pending request is supported */
1911
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301912 return ath6kl_wmi_remain_on_chnl_cmd(ar->wmi, vif->fw_vif_idx,
1913 chan->center_freq, duration);
Jouni Malinen63fa1e02011-08-30 21:57:55 +03001914}
1915
1916static int ath6kl_cancel_remain_on_channel(struct wiphy *wiphy,
1917 struct net_device *dev,
1918 u64 cookie)
1919{
1920 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301921 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen63fa1e02011-08-30 21:57:55 +03001922
1923 if (cookie != 1)
1924 return -ENOENT;
1925
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301926 return ath6kl_wmi_cancel_remain_on_chnl_cmd(ar->wmi, vif->fw_vif_idx);
Jouni Malinen63fa1e02011-08-30 21:57:55 +03001927}
1928
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301929static int ath6kl_send_go_probe_resp(struct ath6kl_vif *vif,
1930 const u8 *buf, size_t len,
1931 unsigned int freq)
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001932{
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301933 struct ath6kl *ar = vif->ar;
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001934 const u8 *pos;
1935 u8 *p2p;
1936 int p2p_len;
1937 int ret;
1938 const struct ieee80211_mgmt *mgmt;
1939
1940 mgmt = (const struct ieee80211_mgmt *) buf;
1941
1942 /* Include P2P IE(s) from the frame generated in user space. */
1943
1944 p2p = kmalloc(len, GFP_KERNEL);
1945 if (p2p == NULL)
1946 return -ENOMEM;
1947 p2p_len = 0;
1948
1949 pos = mgmt->u.probe_resp.variable;
1950 while (pos + 1 < buf + len) {
1951 if (pos + 2 + pos[1] > buf + len)
1952 break;
1953 if (ath6kl_is_p2p_ie(pos)) {
1954 memcpy(p2p + p2p_len, pos, 2 + pos[1]);
1955 p2p_len += 2 + pos[1];
1956 }
1957 pos += 2 + pos[1];
1958 }
1959
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301960 ret = ath6kl_wmi_send_probe_response_cmd(ar->wmi, vif->fw_vif_idx, freq,
1961 mgmt->da, p2p, p2p_len);
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001962 kfree(p2p);
1963 return ret;
1964}
1965
Jouni Malinen8a6c80602011-08-30 21:57:56 +03001966static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
1967 struct ieee80211_channel *chan, bool offchan,
1968 enum nl80211_channel_type channel_type,
1969 bool channel_type_valid, unsigned int wait,
Johannes Berge247bd902011-11-04 11:18:21 +01001970 const u8 *buf, size_t len, bool no_cck,
1971 bool dont_wait_for_ack, u64 *cookie)
Jouni Malinen8a6c80602011-08-30 21:57:56 +03001972{
1973 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301974 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen8a6c80602011-08-30 21:57:56 +03001975 u32 id;
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001976 const struct ieee80211_mgmt *mgmt;
1977
1978 mgmt = (const struct ieee80211_mgmt *) buf;
1979 if (buf + len >= mgmt->u.probe_resp.variable &&
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301980 vif->nw_type == AP_NETWORK && test_bit(CONNECTED, &vif->flags) &&
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001981 ieee80211_is_probe_resp(mgmt->frame_control)) {
1982 /*
1983 * Send Probe Response frame in AP mode using a separate WMI
1984 * command to allow the target to fill in the generic IEs.
1985 */
1986 *cookie = 0; /* TX status not supported */
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301987 return ath6kl_send_go_probe_resp(vif, buf, len,
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001988 chan->center_freq);
1989 }
Jouni Malinen8a6c80602011-08-30 21:57:56 +03001990
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05301991 id = vif->send_action_id++;
Jouni Malinen8a6c80602011-08-30 21:57:56 +03001992 if (id == 0) {
1993 /*
1994 * 0 is a reserved value in the WMI command and shall not be
1995 * used for the command.
1996 */
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05301997 id = vif->send_action_id++;
Jouni Malinen8a6c80602011-08-30 21:57:56 +03001998 }
1999
2000 *cookie = id;
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302001 return ath6kl_wmi_send_action_cmd(ar->wmi, vif->fw_vif_idx, id,
2002 chan->center_freq, wait,
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002003 buf, len);
2004}
2005
Jouni Malinenae32c302011-08-30 21:58:01 +03002006static void ath6kl_mgmt_frame_register(struct wiphy *wiphy,
2007 struct net_device *dev,
2008 u16 frame_type, bool reg)
2009{
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05302010 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinenae32c302011-08-30 21:58:01 +03002011
2012 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: frame_type=0x%x reg=%d\n",
2013 __func__, frame_type, reg);
2014 if (frame_type == IEEE80211_STYPE_PROBE_REQ) {
2015 /*
2016 * Note: This notification callback is not allowed to sleep, so
2017 * we cannot send WMI_PROBE_REQ_REPORT_CMD here. Instead, we
2018 * hardcode target to report Probe Request frames all the time.
2019 */
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05302020 vif->probe_req_report = reg;
Jouni Malinenae32c302011-08-30 21:58:01 +03002021 }
2022}
2023
Jouni Malinenf80574a2011-08-30 21:58:04 +03002024static const struct ieee80211_txrx_stypes
2025ath6kl_mgmt_stypes[NUM_NL80211_IFTYPES] = {
2026 [NL80211_IFTYPE_STATION] = {
2027 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2028 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
2029 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2030 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
2031 },
2032 [NL80211_IFTYPE_P2P_CLIENT] = {
2033 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2034 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
2035 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2036 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
2037 },
2038 [NL80211_IFTYPE_P2P_GO] = {
2039 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2040 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
2041 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
2042 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
2043 },
2044};
2045
Kalle Valobdcd8172011-07-18 00:22:30 +03002046static struct cfg80211_ops ath6kl_cfg80211_ops = {
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302047 .add_virtual_intf = ath6kl_cfg80211_add_iface,
2048 .del_virtual_intf = ath6kl_cfg80211_del_iface,
Kalle Valobdcd8172011-07-18 00:22:30 +03002049 .change_virtual_intf = ath6kl_cfg80211_change_iface,
2050 .scan = ath6kl_cfg80211_scan,
2051 .connect = ath6kl_cfg80211_connect,
2052 .disconnect = ath6kl_cfg80211_disconnect,
2053 .add_key = ath6kl_cfg80211_add_key,
2054 .get_key = ath6kl_cfg80211_get_key,
2055 .del_key = ath6kl_cfg80211_del_key,
2056 .set_default_key = ath6kl_cfg80211_set_default_key,
2057 .set_wiphy_params = ath6kl_cfg80211_set_wiphy_params,
2058 .set_tx_power = ath6kl_cfg80211_set_txpower,
2059 .get_tx_power = ath6kl_cfg80211_get_txpower,
2060 .set_power_mgmt = ath6kl_cfg80211_set_power_mgmt,
2061 .join_ibss = ath6kl_cfg80211_join_ibss,
2062 .leave_ibss = ath6kl_cfg80211_leave_ibss,
2063 .get_station = ath6kl_get_station,
2064 .set_pmksa = ath6kl_set_pmksa,
2065 .del_pmksa = ath6kl_del_pmksa,
2066 .flush_pmksa = ath6kl_flush_pmksa,
Kalle Valo003353b0d2011-09-01 10:14:21 +03002067 CFG80211_TESTMODE_CMD(ath6kl_tm_cmd)
Kalle Valoabcb3442011-07-22 08:26:20 +03002068#ifdef CONFIG_PM
2069 .suspend = ar6k_cfg80211_suspend,
Chilam Ngaa6cffc2011-10-05 10:12:52 +03002070 .resume = ar6k_cfg80211_resume,
Kalle Valoabcb3442011-07-22 08:26:20 +03002071#endif
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03002072 .set_channel = ath6kl_set_channel,
2073 .add_beacon = ath6kl_add_beacon,
2074 .set_beacon = ath6kl_set_beacon,
2075 .del_beacon = ath6kl_del_beacon,
Jouni Malinen23875132011-08-30 21:57:53 +03002076 .change_station = ath6kl_change_station,
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002077 .remain_on_channel = ath6kl_remain_on_channel,
2078 .cancel_remain_on_channel = ath6kl_cancel_remain_on_channel,
Jouni Malinen8a6c80602011-08-30 21:57:56 +03002079 .mgmt_tx = ath6kl_mgmt_tx,
Jouni Malinenae32c302011-08-30 21:58:01 +03002080 .mgmt_frame_register = ath6kl_mgmt_frame_register,
Kalle Valobdcd8172011-07-18 00:22:30 +03002081};
2082
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302083struct ath6kl *ath6kl_core_alloc(struct device *dev)
Kalle Valobdcd8172011-07-18 00:22:30 +03002084{
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03002085 struct ath6kl *ar;
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302086 struct wiphy *wiphy;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302087 u8 ctr;
Kalle Valobdcd8172011-07-18 00:22:30 +03002088
2089 /* create a new wiphy for use with cfg80211 */
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302090 wiphy = wiphy_new(&ath6kl_cfg80211_ops, sizeof(struct ath6kl));
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302091
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302092 if (!wiphy) {
Kalle Valobdcd8172011-07-18 00:22:30 +03002093 ath6kl_err("couldn't allocate wiphy device\n");
Kalle Valobdcd8172011-07-18 00:22:30 +03002094 return NULL;
2095 }
2096
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302097 ar = wiphy_priv(wiphy);
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03002098 ar->p2p = !!ath6kl_p2p;
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302099 ar->wiphy = wiphy;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302100 ar->dev = dev;
2101
2102 spin_lock_init(&ar->lock);
2103 spin_lock_init(&ar->mcastpsq_lock);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05302104 spin_lock_init(&ar->list_lock);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302105
2106 init_waitqueue_head(&ar->event_wq);
2107 sema_init(&ar->sem, 1);
2108
2109 INIT_LIST_HEAD(&ar->amsdu_rx_buffer_queue);
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05302110 INIT_LIST_HEAD(&ar->vif_list);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302111
2112 clear_bit(WMI_ENABLED, &ar->flag);
2113 clear_bit(SKIP_SCAN, &ar->flag);
2114 clear_bit(DESTROY_IN_PROGRESS, &ar->flag);
2115
2116 ar->listen_intvl_t = A_DEFAULT_LISTEN_INTERVAL;
2117 ar->listen_intvl_b = 0;
2118 ar->tx_pwr = 0;
2119
2120 ar->intra_bss = 1;
2121 memset(&ar->sc_params, 0, sizeof(ar->sc_params));
2122 ar->sc_params.short_scan_ratio = WMI_SHORTSCANRATIO_DEFAULT;
2123 ar->sc_params.scan_ctrl_flags = DEFAULT_SCAN_CTRL_FLAGS;
2124 ar->lrssi_roam_threshold = DEF_LRSSI_ROAM_THRESHOLD;
2125
2126 memset((u8 *)ar->sta_list, 0,
2127 AP_MAX_NUM_STA * sizeof(struct ath6kl_sta));
2128
2129 /* Init the PS queues */
2130 for (ctr = 0; ctr < AP_MAX_NUM_STA; ctr++) {
2131 spin_lock_init(&ar->sta_list[ctr].psq_lock);
2132 skb_queue_head_init(&ar->sta_list[ctr].psq);
2133 }
2134
2135 skb_queue_head_init(&ar->mcastpsq);
2136
2137 memcpy(ar->ap_country_code, DEF_AP_COUNTRY_CODE, 3);
2138
2139 return ar;
2140}
2141
2142int ath6kl_register_ieee80211_hw(struct ath6kl *ar)
2143{
2144 struct wiphy *wiphy = ar->wiphy;
2145 int ret;
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03002146
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302147 wiphy->mgmt_stypes = ath6kl_mgmt_stypes;
Jouni Malinenf80574a2011-08-30 21:58:04 +03002148
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302149 wiphy->max_remain_on_channel_duration = 5000;
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002150
Kalle Valobdcd8172011-07-18 00:22:30 +03002151 /* set device pointer for wiphy */
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302152 set_wiphy_dev(wiphy, ar->dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03002153
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302154 wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302155 BIT(NL80211_IFTYPE_ADHOC) |
2156 BIT(NL80211_IFTYPE_AP);
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03002157 if (ar->p2p) {
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302158 wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_GO) |
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302159 BIT(NL80211_IFTYPE_P2P_CLIENT);
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03002160 }
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302161
Kalle Valobdcd8172011-07-18 00:22:30 +03002162 /* max num of ssids that can be probed during scanning */
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302163 wiphy->max_scan_ssids = MAX_PROBED_SSID_INDEX;
2164 wiphy->max_scan_ie_len = 1000; /* FIX: what is correct limit? */
2165 wiphy->bands[IEEE80211_BAND_2GHZ] = &ath6kl_band_2ghz;
2166 wiphy->bands[IEEE80211_BAND_5GHZ] = &ath6kl_band_5ghz;
2167 wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
Kalle Valobdcd8172011-07-18 00:22:30 +03002168
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302169 wiphy->cipher_suites = cipher_suites;
2170 wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
Kalle Valobdcd8172011-07-18 00:22:30 +03002171
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302172 ret = wiphy_register(wiphy);
Kalle Valobdcd8172011-07-18 00:22:30 +03002173 if (ret < 0) {
2174 ath6kl_err("couldn't register wiphy device\n");
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302175 return ret;
Kalle Valobdcd8172011-07-18 00:22:30 +03002176 }
2177
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302178 return 0;
Kalle Valobdcd8172011-07-18 00:22:30 +03002179}
2180
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302181static int ath6kl_init_if_data(struct ath6kl_vif *vif)
Kalle Valobdcd8172011-07-18 00:22:30 +03002182{
Vasanthakumar Thiagarajan2132c692011-10-25 19:34:07 +05302183 vif->aggr_cntxt = aggr_init(vif->ndev);
2184 if (!vif->aggr_cntxt) {
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302185 ath6kl_err("failed to initialize aggr\n");
2186 return -ENOMEM;
2187 }
Kalle Valobdcd8172011-07-18 00:22:30 +03002188
Vasanthakumar Thiagarajande3ad712011-10-25 19:34:08 +05302189 setup_timer(&vif->disconnect_timer, disconnect_timer_handler,
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302190 (unsigned long) vif->ndev);
Vasanthakumar Thiagarajande3ad712011-10-25 19:34:08 +05302191 set_bit(WMM_ENABLED, &vif->flags);
Vasanthakumar Thiagarajan478ac022011-10-25 19:34:19 +05302192 spin_lock_init(&vif->if_lock);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302193
2194 return 0;
2195}
2196
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302197void ath6kl_deinit_if_data(struct ath6kl_vif *vif)
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302198{
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302199 struct ath6kl *ar = vif->ar;
2200
Vasanthakumar Thiagarajan2132c692011-10-25 19:34:07 +05302201 aggr_module_destroy(vif->aggr_cntxt);
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302202
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302203 ar->avail_idx_map |= BIT(vif->fw_vif_idx);
2204
2205 if (vif->nw_type == ADHOC_NETWORK)
2206 ar->ibss_if_active = false;
2207
Vasanthakumar Thiagarajan27929722011-10-25 19:34:21 +05302208 unregister_netdevice(vif->ndev);
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302209
2210 ar->num_vif--;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302211}
2212
2213struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name,
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302214 enum nl80211_iftype type, u8 fw_vif_idx,
2215 u8 nw_type)
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302216{
2217 struct net_device *ndev;
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302218 struct ath6kl_vif *vif;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302219
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302220 ndev = alloc_netdev(sizeof(*vif), name, ether_setup);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302221 if (!ndev)
2222 return NULL;
2223
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302224 vif = netdev_priv(ndev);
2225 ndev->ieee80211_ptr = &vif->wdev;
2226 vif->wdev.wiphy = ar->wiphy;
2227 vif->ar = ar;
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302228 vif->ndev = ndev;
2229 SET_NETDEV_DEV(ndev, wiphy_dev(vif->wdev.wiphy));
2230 vif->wdev.netdev = ndev;
2231 vif->wdev.iftype = type;
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302232 vif->fw_vif_idx = fw_vif_idx;
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302233 vif->nw_type = vif->next_mode = nw_type;
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302234 ar->wdev = &vif->wdev;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302235
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302236 memcpy(ndev->dev_addr, ar->mac_addr, ETH_ALEN);
2237 if (fw_vif_idx != 0)
2238 ndev->dev_addr[0] = (ndev->dev_addr[0] ^ (1 << fw_vif_idx)) |
2239 0x2;
2240
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302241 init_netdev(ndev);
2242
Vasanthakumar Thiagarajane29f25f2011-10-25 19:34:15 +05302243 ath6kl_init_control_info(vif);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302244
2245 /* TODO: Pass interface specific pointer instead of ar */
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302246 if (ath6kl_init_if_data(vif))
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302247 goto err;
2248
Vasanthakumar Thiagarajan27929722011-10-25 19:34:21 +05302249 if (register_netdevice(ndev))
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302250 goto err;
2251
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302252 ar->avail_idx_map &= ~BIT(fw_vif_idx);
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +05302253 vif->sme_state = SME_DISCONNECTED;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302254 set_bit(WLAN_ENABLED, &vif->flags);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302255 ar->wlan_pwr_state = WLAN_POWER_STATE_ON;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302256 set_bit(NETDEV_REGISTERED, &vif->flags);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302257
Vasanthakumar Thiagarajan55055972011-10-25 19:34:23 +05302258 if (type == NL80211_IFTYPE_ADHOC)
2259 ar->ibss_if_active = true;
2260
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05302261 spin_lock(&ar->list_lock);
2262 list_add_tail(&vif->list, &ar->vif_list);
2263 spin_unlock(&ar->list_lock);
2264
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302265 return ndev;
2266
2267err:
Vasanthakumar Thiagarajan27929722011-10-25 19:34:21 +05302268 aggr_module_destroy(vif->aggr_cntxt);
2269 free_netdev(ndev);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302270 return NULL;
2271}
2272
2273void ath6kl_deinit_ieee80211_hw(struct ath6kl *ar)
2274{
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302275 wiphy_unregister(ar->wiphy);
2276 wiphy_free(ar->wiphy);
Kalle Valobdcd8172011-07-18 00:22:30 +03002277}