blob: b242b31eb19e9fefa1a4a731336b4a8cb94bc298 [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
231static bool ath6kl_cfg80211_ready(struct ath6kl *ar)
232{
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530233 struct ath6kl_vif *vif = ar->vif;
234
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
Kalle Valobdcd8172011-07-18 00:22:30 +0300296static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
297 struct cfg80211_connect_params *sme)
298{
299 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530300 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +0300301 int status;
302
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530303 vif->sme_state = SME_CONNECTING;
Kalle Valobdcd8172011-07-18 00:22:30 +0300304
305 if (!ath6kl_cfg80211_ready(ar))
306 return -EIO;
307
308 if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) {
309 ath6kl_err("destroy in progress\n");
310 return -EBUSY;
311 }
312
313 if (test_bit(SKIP_SCAN, &ar->flag) &&
314 ((sme->channel && sme->channel->center_freq == 0) ||
315 (sme->bssid && is_zero_ether_addr(sme->bssid)))) {
316 ath6kl_err("SkipScan: channel or bssid invalid\n");
317 return -EINVAL;
318 }
319
320 if (down_interruptible(&ar->sem)) {
321 ath6kl_err("busy, couldn't get access\n");
322 return -ERESTARTSYS;
323 }
324
325 if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) {
326 ath6kl_err("busy, destroy in progress\n");
327 up(&ar->sem);
328 return -EBUSY;
329 }
330
331 if (ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)]) {
332 /*
333 * sleep until the command queue drains
334 */
335 wait_event_interruptible_timeout(ar->event_wq,
336 ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)] == 0,
337 WMI_TIMEOUT);
338 if (signal_pending(current)) {
339 ath6kl_err("cmd queue drain timeout\n");
340 up(&ar->sem);
341 return -EINTR;
342 }
343 }
344
Kevin Fang6981ffd2011-10-07 08:51:19 +0800345 if (sme->ie && (sme->ie_len > 0)) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530346 status = ath6kl_set_assoc_req_ies(vif, sme->ie, sme->ie_len);
Kevin Fang6981ffd2011-10-07 08:51:19 +0800347 if (status)
348 return status;
349 }
350
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530351 if (test_bit(CONNECTED, &vif->flags) &&
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530352 vif->ssid_len == sme->ssid_len &&
353 !memcmp(vif->ssid, sme->ssid, vif->ssid_len)) {
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +0530354 vif->reconnect_flag = true;
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530355 status = ath6kl_wmi_reconnect_cmd(ar->wmi, vif->fw_vif_idx,
356 vif->req_bssid,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +0530357 vif->ch_hint);
Kalle Valobdcd8172011-07-18 00:22:30 +0300358
359 up(&ar->sem);
360 if (status) {
361 ath6kl_err("wmi_reconnect_cmd failed\n");
362 return -EIO;
363 }
364 return 0;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530365 } else if (vif->ssid_len == sme->ssid_len &&
366 !memcmp(vif->ssid, sme->ssid, vif->ssid_len)) {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530367 ath6kl_disconnect(vif);
Kalle Valobdcd8172011-07-18 00:22:30 +0300368 }
369
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530370 memset(vif->ssid, 0, sizeof(vif->ssid));
371 vif->ssid_len = sme->ssid_len;
372 memcpy(vif->ssid, sme->ssid, sme->ssid_len);
Kalle Valobdcd8172011-07-18 00:22:30 +0300373
374 if (sme->channel)
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +0530375 vif->ch_hint = sme->channel->center_freq;
Kalle Valobdcd8172011-07-18 00:22:30 +0300376
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +0530377 memset(vif->req_bssid, 0, sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +0300378 if (sme->bssid && !is_broadcast_ether_addr(sme->bssid))
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +0530379 memcpy(vif->req_bssid, sme->bssid, sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +0300380
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530381 ath6kl_set_wpa_version(vif, sme->crypto.wpa_versions);
Kalle Valobdcd8172011-07-18 00:22:30 +0300382
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530383 status = ath6kl_set_auth_type(vif, sme->auth_type);
Kalle Valobdcd8172011-07-18 00:22:30 +0300384 if (status) {
385 up(&ar->sem);
386 return status;
387 }
388
389 if (sme->crypto.n_ciphers_pairwise)
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530390 ath6kl_set_cipher(vif, sme->crypto.ciphers_pairwise[0], true);
Kalle Valobdcd8172011-07-18 00:22:30 +0300391 else
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530392 ath6kl_set_cipher(vif, 0, true);
Kalle Valobdcd8172011-07-18 00:22:30 +0300393
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530394 ath6kl_set_cipher(vif, sme->crypto.cipher_group, false);
Kalle Valobdcd8172011-07-18 00:22:30 +0300395
396 if (sme->crypto.n_akm_suites)
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530397 ath6kl_set_key_mgmt(vif, sme->crypto.akm_suites[0]);
Kalle Valobdcd8172011-07-18 00:22:30 +0300398
399 if ((sme->key_len) &&
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530400 (vif->auth_mode == NONE_AUTH) &&
401 (vif->prwise_crypto == WEP_CRYPT)) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300402 struct ath6kl_key *key = NULL;
403
404 if (sme->key_idx < WMI_MIN_KEY_INDEX ||
405 sme->key_idx > WMI_MAX_KEY_INDEX) {
406 ath6kl_err("key index %d out of bounds\n",
407 sme->key_idx);
408 up(&ar->sem);
409 return -ENOENT;
410 }
411
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +0530412 key = &vif->keys[sme->key_idx];
Kalle Valobdcd8172011-07-18 00:22:30 +0300413 key->key_len = sme->key_len;
414 memcpy(key->key, sme->key, key->key_len);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530415 key->cipher = vif->prwise_crypto;
416 vif->def_txkey_index = sme->key_idx;
Kalle Valobdcd8172011-07-18 00:22:30 +0300417
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530418 ath6kl_wmi_addkey_cmd(ar->wmi, vif->fw_vif_idx, sme->key_idx,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530419 vif->prwise_crypto,
Kalle Valobdcd8172011-07-18 00:22:30 +0300420 GROUP_USAGE | TX_USAGE,
421 key->key_len,
422 NULL,
423 key->key, KEY_OP_INIT_VAL, NULL,
424 NO_SYNC_WMIFLAG);
425 }
426
427 if (!ar->usr_bss_filter) {
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530428 clear_bit(CLEAR_BSSFILTER_ON_BEACON, &vif->flags);
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530429 if (ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx,
430 ALL_BSS_FILTER, 0) != 0) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300431 ath6kl_err("couldn't set bss filtering\n");
432 up(&ar->sem);
433 return -EIO;
434 }
435 }
436
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +0530437 vif->nw_type = vif->next_mode;
Kalle Valobdcd8172011-07-18 00:22:30 +0300438
439 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
440 "%s: connect called with authmode %d dot11 auth %d"
441 " PW crypto %d PW crypto len %d GRP crypto %d"
442 " GRP crypto len %d channel hint %u\n",
443 __func__,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530444 vif->auth_mode, vif->dot11_auth_mode, vif->prwise_crypto,
445 vif->prwise_crypto_len, vif->grp_crypto,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +0530446 vif->grp_crypto_len, vif->ch_hint);
Kalle Valobdcd8172011-07-18 00:22:30 +0300447
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +0530448 vif->reconnect_flag = 0;
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530449 status = ath6kl_wmi_connect_cmd(ar->wmi, vif->fw_vif_idx, vif->nw_type,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530450 vif->dot11_auth_mode, vif->auth_mode,
451 vif->prwise_crypto,
452 vif->prwise_crypto_len,
453 vif->grp_crypto, vif->grp_crypto_len,
454 vif->ssid_len, vif->ssid,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +0530455 vif->req_bssid, vif->ch_hint,
Kalle Valobdcd8172011-07-18 00:22:30 +0300456 ar->connect_ctrl_flags);
457
458 up(&ar->sem);
459
460 if (status == -EINVAL) {
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530461 memset(vif->ssid, 0, sizeof(vif->ssid));
462 vif->ssid_len = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +0300463 ath6kl_err("invalid request\n");
464 return -ENOENT;
465 } else if (status) {
466 ath6kl_err("ath6kl_wmi_connect_cmd failed\n");
467 return -EIO;
468 }
469
470 if ((!(ar->connect_ctrl_flags & CONNECT_DO_WPA_OFFLOAD)) &&
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530471 ((vif->auth_mode == WPA_PSK_AUTH)
472 || (vif->auth_mode == WPA2_PSK_AUTH))) {
Vasanthakumar Thiagarajande3ad712011-10-25 19:34:08 +0530473 mod_timer(&vif->disconnect_timer,
Kalle Valobdcd8172011-07-18 00:22:30 +0300474 jiffies + msecs_to_jiffies(DISCON_TIMER_INTVAL));
475 }
476
477 ar->connect_ctrl_flags &= ~CONNECT_DO_WPA_OFFLOAD;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530478 set_bit(CONNECT_PEND, &vif->flags);
Kalle Valobdcd8172011-07-18 00:22:30 +0300479
480 return 0;
481}
482
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530483static int ath6kl_add_bss_if_needed(struct ath6kl_vif *vif, const u8 *bssid,
Jouni Malinen01cac472011-09-19 19:14:59 +0300484 struct ieee80211_channel *chan,
485 const u8 *beacon_ie, size_t beacon_ie_len)
486{
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530487 struct ath6kl *ar = vif->ar;
Jouni Malinen01cac472011-09-19 19:14:59 +0300488 struct cfg80211_bss *bss;
489 u8 *ie;
490
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +0530491 bss = cfg80211_get_bss(ar->wiphy, chan, bssid,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530492 vif->ssid, vif->ssid_len, WLAN_CAPABILITY_ESS,
Jouni Malinen01cac472011-09-19 19:14:59 +0300493 WLAN_CAPABILITY_ESS);
494 if (bss == NULL) {
495 /*
496 * Since cfg80211 may not yet know about the BSS,
497 * generate a partial entry until the first BSS info
498 * event becomes available.
499 *
500 * Prepend SSID element since it is not included in the Beacon
501 * IEs from the target.
502 */
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530503 ie = kmalloc(2 + vif->ssid_len + beacon_ie_len, GFP_KERNEL);
Jouni Malinen01cac472011-09-19 19:14:59 +0300504 if (ie == NULL)
505 return -ENOMEM;
506 ie[0] = WLAN_EID_SSID;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530507 ie[1] = vif->ssid_len;
508 memcpy(ie + 2, vif->ssid, vif->ssid_len);
509 memcpy(ie + 2 + vif->ssid_len, beacon_ie, beacon_ie_len);
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +0530510 bss = cfg80211_inform_bss(ar->wiphy, chan,
Jouni Malinen01cac472011-09-19 19:14:59 +0300511 bssid, 0, WLAN_CAPABILITY_ESS, 100,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530512 ie, 2 + vif->ssid_len + beacon_ie_len,
Jouni Malinen01cac472011-09-19 19:14:59 +0300513 0, GFP_KERNEL);
514 if (bss)
515 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "added dummy bss for "
516 "%pM prior to indicating connect/roamed "
517 "event\n", bssid);
518 kfree(ie);
519 } else
520 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "cfg80211 already has a bss "
521 "entry\n");
522
523 if (bss == NULL)
524 return -ENOMEM;
525
526 cfg80211_put_bss(bss);
527
528 return 0;
529}
530
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530531void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel,
Kalle Valobdcd8172011-07-18 00:22:30 +0300532 u8 *bssid, u16 listen_intvl,
533 u16 beacon_intvl,
534 enum network_type nw_type,
535 u8 beacon_ie_len, u8 assoc_req_len,
536 u8 assoc_resp_len, u8 *assoc_info)
537{
Jouni Malinen01cac472011-09-19 19:14:59 +0300538 struct ieee80211_channel *chan;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530539 struct ath6kl *ar = vif->ar;
Kalle Valobdcd8172011-07-18 00:22:30 +0300540
541 /* capinfo + listen interval */
542 u8 assoc_req_ie_offset = sizeof(u16) + sizeof(u16);
543
544 /* capinfo + status code + associd */
545 u8 assoc_resp_ie_offset = sizeof(u16) + sizeof(u16) + sizeof(u16);
546
547 u8 *assoc_req_ie = assoc_info + beacon_ie_len + assoc_req_ie_offset;
548 u8 *assoc_resp_ie = assoc_info + beacon_ie_len + assoc_req_len +
549 assoc_resp_ie_offset;
550
551 assoc_req_len -= assoc_req_ie_offset;
552 assoc_resp_len -= assoc_resp_ie_offset;
553
Jouni Malinen32c10872011-09-19 19:15:07 +0300554 /*
555 * Store Beacon interval here; DTIM period will be available only once
556 * a Beacon frame from the AP is seen.
557 */
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +0530558 vif->assoc_bss_beacon_int = beacon_intvl;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530559 clear_bit(DTIM_PERIOD_AVAIL, &vif->flags);
Jouni Malinen32c10872011-09-19 19:15:07 +0300560
Kalle Valobdcd8172011-07-18 00:22:30 +0300561 if (nw_type & ADHOC_NETWORK) {
562 if (ar->wdev->iftype != NL80211_IFTYPE_ADHOC) {
563 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
564 "%s: ath6k not in ibss mode\n", __func__);
565 return;
566 }
567 }
568
569 if (nw_type & INFRA_NETWORK) {
Jouni Malinen6b5e5d22011-08-30 21:58:05 +0300570 if (ar->wdev->iftype != NL80211_IFTYPE_STATION &&
571 ar->wdev->iftype != NL80211_IFTYPE_P2P_CLIENT) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300572 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
573 "%s: ath6k not in station mode\n", __func__);
574 return;
575 }
576 }
577
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +0530578 chan = ieee80211_get_channel(ar->wiphy, (int) channel);
Kalle Valobdcd8172011-07-18 00:22:30 +0300579
Kalle Valobdcd8172011-07-18 00:22:30 +0300580
581 if (nw_type & ADHOC_NETWORK) {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530582 cfg80211_ibss_joined(vif->ndev, bssid, GFP_KERNEL);
Kalle Valobdcd8172011-07-18 00:22:30 +0300583 return;
584 }
585
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530586 if (ath6kl_add_bss_if_needed(vif, bssid, chan, assoc_info,
Jouni Malinen01cac472011-09-19 19:14:59 +0300587 beacon_ie_len) < 0) {
588 ath6kl_err("could not add cfg80211 bss entry for "
589 "connect/roamed notification\n");
590 return;
591 }
592
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530593 if (vif->sme_state == SME_CONNECTING) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300594 /* inform connect result to cfg80211 */
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530595 vif->sme_state = SME_CONNECTED;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530596 cfg80211_connect_result(vif->ndev, bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +0300597 assoc_req_ie, assoc_req_len,
598 assoc_resp_ie, assoc_resp_len,
599 WLAN_STATUS_SUCCESS, GFP_KERNEL);
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530600 } else if (vif->sme_state == SME_CONNECTED) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300601 /* inform roam event to cfg80211 */
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530602 cfg80211_roamed(vif->ndev, chan, bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +0300603 assoc_req_ie, assoc_req_len,
604 assoc_resp_ie, assoc_resp_len, GFP_KERNEL);
605 }
606}
607
608static int ath6kl_cfg80211_disconnect(struct wiphy *wiphy,
609 struct net_device *dev, u16 reason_code)
610{
611 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(dev);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530612 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +0300613
614 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: reason=%u\n", __func__,
615 reason_code);
616
617 if (!ath6kl_cfg80211_ready(ar))
618 return -EIO;
619
620 if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) {
621 ath6kl_err("busy, destroy in progress\n");
622 return -EBUSY;
623 }
624
625 if (down_interruptible(&ar->sem)) {
626 ath6kl_err("busy, couldn't get access\n");
627 return -ERESTARTSYS;
628 }
629
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +0530630 vif->reconnect_flag = 0;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530631 ath6kl_disconnect(vif);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530632 memset(vif->ssid, 0, sizeof(vif->ssid));
633 vif->ssid_len = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +0300634
635 if (!test_bit(SKIP_SCAN, &ar->flag))
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +0530636 memset(vif->req_bssid, 0, sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +0300637
638 up(&ar->sem);
639
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530640 vif->sme_state = SME_DISCONNECTED;
Vasanthakumar Thiagarajan170826d2011-09-10 15:26:35 +0530641
Kalle Valobdcd8172011-07-18 00:22:30 +0300642 return 0;
643}
644
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530645void ath6kl_cfg80211_disconnect_event(struct ath6kl_vif *vif, u8 reason,
Kalle Valobdcd8172011-07-18 00:22:30 +0300646 u8 *bssid, u8 assoc_resp_len,
647 u8 *assoc_info, u16 proto_reason)
648{
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530649 struct ath6kl *ar = vif->ar;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530650
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530651 if (vif->scan_req) {
652 cfg80211_scan_done(vif->scan_req, true);
653 vif->scan_req = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +0300654 }
655
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +0530656 if (vif->nw_type & ADHOC_NETWORK) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300657 if (ar->wdev->iftype != NL80211_IFTYPE_ADHOC) {
658 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
659 "%s: ath6k not in ibss mode\n", __func__);
660 return;
661 }
662 memset(bssid, 0, ETH_ALEN);
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530663 cfg80211_ibss_joined(vif->ndev, bssid, GFP_KERNEL);
Kalle Valobdcd8172011-07-18 00:22:30 +0300664 return;
665 }
666
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +0530667 if (vif->nw_type & INFRA_NETWORK) {
Jouni Malinen6b5e5d22011-08-30 21:58:05 +0300668 if (ar->wdev->iftype != NL80211_IFTYPE_STATION &&
669 ar->wdev->iftype != NL80211_IFTYPE_P2P_CLIENT) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300670 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
671 "%s: ath6k not in station mode\n", __func__);
672 return;
673 }
674 }
675
Vasanthakumar Thiagarajan1de547d2011-09-23 10:57:50 +0530676 /*
677 * Send a disconnect command to target when a disconnect event is
678 * received with reason code other than 3 (DISCONNECT_CMD - disconnect
679 * request from host) to make the firmware stop trying to connect even
680 * after giving disconnect event. There will be one more disconnect
681 * event for this disconnect command with reason code DISCONNECT_CMD
682 * which will be notified to cfg80211.
683 */
Kalle Valobdcd8172011-07-18 00:22:30 +0300684
Vasanthakumar Thiagarajan1de547d2011-09-23 10:57:50 +0530685 if (reason != DISCONNECT_CMD) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530686 ath6kl_wmi_disconnect_cmd(ar->wmi, vif->fw_vif_idx);
Kalle Valobdcd8172011-07-18 00:22:30 +0300687 return;
688 }
689
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530690 clear_bit(CONNECT_PEND, &vif->flags);
Kalle Valobdcd8172011-07-18 00:22:30 +0300691
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530692 if (vif->sme_state == SME_CONNECTING) {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530693 cfg80211_connect_result(vif->ndev,
Vasanthakumar Thiagarajanac59a2b2011-09-10 15:26:34 +0530694 bssid, NULL, 0,
695 NULL, 0,
696 WLAN_STATUS_UNSPECIFIED_FAILURE,
697 GFP_KERNEL);
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530698 } else if (vif->sme_state == SME_CONNECTED) {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530699 cfg80211_disconnected(vif->ndev, reason,
Vasanthakumar Thiagarajanac59a2b2011-09-10 15:26:34 +0530700 NULL, 0, GFP_KERNEL);
Kalle Valobdcd8172011-07-18 00:22:30 +0300701 }
702
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530703 vif->sme_state = SME_DISCONNECTED;
Kalle Valobdcd8172011-07-18 00:22:30 +0300704}
705
Kalle Valobdcd8172011-07-18 00:22:30 +0300706static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
707 struct cfg80211_scan_request *request)
708{
709 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530710 struct ath6kl_vif *vif = netdev_priv(ndev);
Edward Lu1276c9e2011-08-30 21:58:00 +0300711 s8 n_channels = 0;
712 u16 *channels = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +0300713 int ret = 0;
Vasanthakumar Thiagarajanf1f92172011-10-01 16:12:36 +0530714 u32 force_fg_scan = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +0300715
716 if (!ath6kl_cfg80211_ready(ar))
717 return -EIO;
718
719 if (!ar->usr_bss_filter) {
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530720 clear_bit(CLEAR_BSSFILTER_ON_BEACON, &vif->flags);
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300721 ret = ath6kl_wmi_bssfilter_cmd(
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530722 ar->wmi, vif->fw_vif_idx,
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530723 (test_bit(CONNECTED, &vif->flags) ?
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300724 ALL_BUT_BSS_FILTER : ALL_BSS_FILTER), 0);
725 if (ret) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300726 ath6kl_err("couldn't set bss filtering\n");
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300727 return ret;
Kalle Valobdcd8172011-07-18 00:22:30 +0300728 }
729 }
730
731 if (request->n_ssids && request->ssids[0].ssid_len) {
732 u8 i;
733
734 if (request->n_ssids > (MAX_PROBED_SSID_INDEX - 1))
735 request->n_ssids = MAX_PROBED_SSID_INDEX - 1;
736
737 for (i = 0; i < request->n_ssids; i++)
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530738 ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx,
739 i + 1, SPECIFIC_SSID_FLAG,
Kalle Valobdcd8172011-07-18 00:22:30 +0300740 request->ssids[i].ssid_len,
741 request->ssids[i].ssid);
742 }
743
Jouni Malinenb84da8c2011-08-30 21:57:59 +0300744 if (request->ie) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530745 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
746 WMI_FRAME_PROBE_REQ,
Jouni Malinenb84da8c2011-08-30 21:57:59 +0300747 request->ie, request->ie_len);
748 if (ret) {
749 ath6kl_err("failed to set Probe Request appie for "
750 "scan");
751 return ret;
752 }
753 }
754
Jouni Malinen11869be2011-09-02 20:07:06 +0300755 /*
756 * Scan only the requested channels if the request specifies a set of
757 * channels. If the list is longer than the target supports, do not
758 * configure the list and instead, scan all available channels.
759 */
760 if (request->n_channels > 0 &&
761 request->n_channels <= WMI_MAX_CHANNELS) {
Edward Lu1276c9e2011-08-30 21:58:00 +0300762 u8 i;
763
Jouni Malinen11869be2011-09-02 20:07:06 +0300764 n_channels = request->n_channels;
Edward Lu1276c9e2011-08-30 21:58:00 +0300765
766 channels = kzalloc(n_channels * sizeof(u16), GFP_KERNEL);
767 if (channels == NULL) {
768 ath6kl_warn("failed to set scan channels, "
769 "scan all channels");
770 n_channels = 0;
771 }
772
773 for (i = 0; i < n_channels; i++)
774 channels[i] = request->channels[i]->center_freq;
775 }
776
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530777 if (test_bit(CONNECTED, &vif->flags))
Vasanthakumar Thiagarajanf1f92172011-10-01 16:12:36 +0530778 force_fg_scan = 1;
779
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530780 ret = ath6kl_wmi_startscan_cmd(ar->wmi, vif->fw_vif_idx, WMI_LONG_SCAN,
781 force_fg_scan, false, 0, 0, n_channels,
782 channels);
Jouni Malinen1b1e6ee2011-08-30 21:58:10 +0300783 if (ret)
Kalle Valobdcd8172011-07-18 00:22:30 +0300784 ath6kl_err("wmi_startscan_cmd failed\n");
Jouni Malinen11869be2011-09-02 20:07:06 +0300785 else
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530786 vif->scan_req = request;
Kalle Valobdcd8172011-07-18 00:22:30 +0300787
Edward Lu1276c9e2011-08-30 21:58:00 +0300788 kfree(channels);
789
Kalle Valobdcd8172011-07-18 00:22:30 +0300790 return ret;
791}
792
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530793void ath6kl_cfg80211_scan_complete_event(struct ath6kl_vif *vif, int status)
Kalle Valobdcd8172011-07-18 00:22:30 +0300794{
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530795 struct ath6kl *ar = vif->ar;
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300796 int i;
Kalle Valobdcd8172011-07-18 00:22:30 +0300797
798 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: status %d\n", __func__, status);
799
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530800 if (!vif->scan_req)
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300801 return;
Kalle Valobdcd8172011-07-18 00:22:30 +0300802
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300803 if ((status == -ECANCELED) || (status == -EBUSY)) {
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530804 cfg80211_scan_done(vif->scan_req, true);
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300805 goto out;
Kalle Valobdcd8172011-07-18 00:22:30 +0300806 }
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300807
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530808 cfg80211_scan_done(vif->scan_req, false);
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300809
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530810 if (vif->scan_req->n_ssids && vif->scan_req->ssids[0].ssid_len) {
811 for (i = 0; i < vif->scan_req->n_ssids; i++) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530812 ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx,
813 i + 1, DISABLE_SSID_FLAG,
Kalle Valo6fd1eac2011-07-21 10:22:50 +0300814 0, NULL);
815 }
816 }
817
818out:
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +0530819 vif->scan_req = NULL;
Kalle Valobdcd8172011-07-18 00:22:30 +0300820}
821
822static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
823 u8 key_index, bool pairwise,
824 const u8 *mac_addr,
825 struct key_params *params)
826{
827 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530828 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +0300829 struct ath6kl_key *key = NULL;
830 u8 key_usage;
831 u8 key_type;
832 int status = 0;
833
834 if (!ath6kl_cfg80211_ready(ar))
835 return -EIO;
836
Jouni Malinen837cb972011-10-11 17:31:57 +0300837 if (params->cipher == CCKM_KRK_CIPHER_SUITE) {
838 if (params->key_len != WMI_KRK_LEN)
839 return -EINVAL;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +0530840 return ath6kl_wmi_add_krk_cmd(ar->wmi, vif->fw_vif_idx,
841 params->key);
Jouni Malinen837cb972011-10-11 17:31:57 +0300842 }
843
Kalle Valobdcd8172011-07-18 00:22:30 +0300844 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
845 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
846 "%s: key index %d out of bounds\n", __func__,
847 key_index);
848 return -ENOENT;
849 }
850
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +0530851 key = &vif->keys[key_index];
Kalle Valobdcd8172011-07-18 00:22:30 +0300852 memset(key, 0, sizeof(struct ath6kl_key));
853
854 if (pairwise)
855 key_usage = PAIRWISE_USAGE;
856 else
857 key_usage = GROUP_USAGE;
858
859 if (params) {
860 if (params->key_len > WLAN_MAX_KEY_LEN ||
861 params->seq_len > sizeof(key->seq))
862 return -EINVAL;
863
864 key->key_len = params->key_len;
865 memcpy(key->key, params->key, key->key_len);
866 key->seq_len = params->seq_len;
867 memcpy(key->seq, params->seq, key->seq_len);
868 key->cipher = params->cipher;
869 }
870
871 switch (key->cipher) {
872 case WLAN_CIPHER_SUITE_WEP40:
873 case WLAN_CIPHER_SUITE_WEP104:
874 key_type = WEP_CRYPT;
875 break;
876
877 case WLAN_CIPHER_SUITE_TKIP:
878 key_type = TKIP_CRYPT;
879 break;
880
881 case WLAN_CIPHER_SUITE_CCMP:
882 key_type = AES_CRYPT;
883 break;
884
885 default:
886 return -ENOTSUPP;
887 }
888
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530889 if (((vif->auth_mode == WPA_PSK_AUTH)
890 || (vif->auth_mode == WPA2_PSK_AUTH))
Kalle Valobdcd8172011-07-18 00:22:30 +0300891 && (key_usage & GROUP_USAGE))
Vasanthakumar Thiagarajande3ad712011-10-25 19:34:08 +0530892 del_timer(&vif->disconnect_timer);
Kalle Valobdcd8172011-07-18 00:22:30 +0300893
894 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
895 "%s: index %d, key_len %d, key_type 0x%x, key_usage 0x%x, seq_len %d\n",
896 __func__, key_index, key->key_len, key_type,
897 key_usage, key->seq_len);
898
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +0530899 vif->def_txkey_index = key_index;
Jouni Malinen9a5b1312011-08-30 21:57:52 +0300900
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +0530901 if (vif->nw_type == AP_NETWORK && !pairwise &&
Jouni Malinen9a5b1312011-08-30 21:57:52 +0300902 (key_type == TKIP_CRYPT || key_type == AES_CRYPT) && params) {
903 ar->ap_mode_bkey.valid = true;
904 ar->ap_mode_bkey.key_index = key_index;
905 ar->ap_mode_bkey.key_type = key_type;
906 ar->ap_mode_bkey.key_len = key->key_len;
907 memcpy(ar->ap_mode_bkey.key, key->key, key->key_len);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530908 if (!test_bit(CONNECTED, &vif->flags)) {
Jouni Malinen9a5b1312011-08-30 21:57:52 +0300909 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delay initial group "
910 "key configuration until AP mode has been "
911 "started\n");
912 /*
913 * The key will be set in ath6kl_connect_ap_mode() once
914 * the connected event is received from the target.
915 */
916 return 0;
917 }
918 }
919
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +0530920 if (vif->next_mode == AP_NETWORK && key_type == WEP_CRYPT &&
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +0530921 !test_bit(CONNECTED, &vif->flags)) {
Jouni Malinen151411e2011-09-15 15:10:16 +0300922 /*
923 * Store the key locally so that it can be re-configured after
924 * the AP mode has properly started
925 * (ath6kl_install_statioc_wep_keys).
926 */
927 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delay WEP key configuration "
928 "until AP mode has been started\n");
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +0530929 vif->wep_key_list[key_index].key_len = key->key_len;
930 memcpy(vif->wep_key_list[key_index].key, key->key,
931 key->key_len);
Jouni Malinen151411e2011-09-15 15:10:16 +0300932 return 0;
933 }
934
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530935 status = ath6kl_wmi_addkey_cmd(ar->wmi, vif->fw_vif_idx,
936 vif->def_txkey_index,
Kalle Valobdcd8172011-07-18 00:22:30 +0300937 key_type, key_usage, key->key_len,
938 key->seq, key->key, KEY_OP_INIT_VAL,
939 (u8 *) mac_addr, SYNC_BOTH_WMIFLAG);
940
941 if (status)
942 return -EIO;
943
944 return 0;
945}
946
947static int ath6kl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
948 u8 key_index, bool pairwise,
949 const u8 *mac_addr)
950{
951 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +0530952 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +0300953
954 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
955
956 if (!ath6kl_cfg80211_ready(ar))
957 return -EIO;
958
959 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
960 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
961 "%s: key index %d out of bounds\n", __func__,
962 key_index);
963 return -ENOENT;
964 }
965
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +0530966 if (!vif->keys[key_index].key_len) {
Kalle Valobdcd8172011-07-18 00:22:30 +0300967 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
968 "%s: index %d is empty\n", __func__, key_index);
969 return 0;
970 }
971
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +0530972 vif->keys[key_index].key_len = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +0300973
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530974 return ath6kl_wmi_deletekey_cmd(ar->wmi, vif->fw_vif_idx, key_index);
Kalle Valobdcd8172011-07-18 00:22:30 +0300975}
976
977static int ath6kl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
978 u8 key_index, bool pairwise,
979 const u8 *mac_addr, void *cookie,
980 void (*callback) (void *cookie,
981 struct key_params *))
982{
983 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +0530984 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +0300985 struct ath6kl_key *key = NULL;
986 struct key_params params;
987
988 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
989
990 if (!ath6kl_cfg80211_ready(ar))
991 return -EIO;
992
993 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
994 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
995 "%s: key index %d out of bounds\n", __func__,
996 key_index);
997 return -ENOENT;
998 }
999
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301000 key = &vif->keys[key_index];
Kalle Valobdcd8172011-07-18 00:22:30 +03001001 memset(&params, 0, sizeof(params));
1002 params.cipher = key->cipher;
1003 params.key_len = key->key_len;
1004 params.seq_len = key->seq_len;
1005 params.seq = key->seq;
1006 params.key = key->key;
1007
1008 callback(cookie, &params);
1009
1010 return key->key_len ? 0 : -ENOENT;
1011}
1012
1013static int ath6kl_cfg80211_set_default_key(struct wiphy *wiphy,
1014 struct net_device *ndev,
1015 u8 key_index, bool unicast,
1016 bool multicast)
1017{
1018 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301019 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001020 struct ath6kl_key *key = NULL;
1021 int status = 0;
1022 u8 key_usage;
Edward Lu229ed6b2011-08-30 21:58:07 +03001023 enum crypto_type key_type = NONE_CRYPT;
Kalle Valobdcd8172011-07-18 00:22:30 +03001024
1025 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
1026
1027 if (!ath6kl_cfg80211_ready(ar))
1028 return -EIO;
1029
1030 if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
1031 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1032 "%s: key index %d out of bounds\n",
1033 __func__, key_index);
1034 return -ENOENT;
1035 }
1036
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301037 if (!vif->keys[key_index].key_len) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001038 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: invalid key index %d\n",
1039 __func__, key_index);
1040 return -EINVAL;
1041 }
1042
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301043 vif->def_txkey_index = key_index;
Vasanthakumar Thiagarajan6f2a73f2011-10-25 19:34:06 +05301044 key = &vif->keys[vif->def_txkey_index];
Kalle Valobdcd8172011-07-18 00:22:30 +03001045 key_usage = GROUP_USAGE;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301046 if (vif->prwise_crypto == WEP_CRYPT)
Kalle Valobdcd8172011-07-18 00:22:30 +03001047 key_usage |= TX_USAGE;
Edward Lu229ed6b2011-08-30 21:58:07 +03001048 if (unicast)
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301049 key_type = vif->prwise_crypto;
Edward Lu229ed6b2011-08-30 21:58:07 +03001050 if (multicast)
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301051 key_type = vif->grp_crypto;
Kalle Valobdcd8172011-07-18 00:22:30 +03001052
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301053 if (vif->next_mode == AP_NETWORK && !test_bit(CONNECTED, &vif->flags))
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001054 return 0; /* Delay until AP mode has been started */
1055
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301056 status = ath6kl_wmi_addkey_cmd(ar->wmi, vif->fw_vif_idx,
1057 vif->def_txkey_index,
Edward Lu229ed6b2011-08-30 21:58:07 +03001058 key_type, key_usage,
Kalle Valobdcd8172011-07-18 00:22:30 +03001059 key->key_len, key->seq, key->key,
1060 KEY_OP_INIT_VAL, NULL,
1061 SYNC_BOTH_WMIFLAG);
1062 if (status)
1063 return -EIO;
1064
1065 return 0;
1066}
1067
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301068void ath6kl_cfg80211_tkip_micerr_event(struct ath6kl_vif *vif, u8 keyid,
Kalle Valobdcd8172011-07-18 00:22:30 +03001069 bool ismcast)
1070{
1071 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1072 "%s: keyid %d, ismcast %d\n", __func__, keyid, ismcast);
1073
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301074 cfg80211_michael_mic_failure(vif->ndev, vif->bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +03001075 (ismcast ? NL80211_KEYTYPE_GROUP :
1076 NL80211_KEYTYPE_PAIRWISE), keyid, NULL,
1077 GFP_KERNEL);
1078}
1079
1080static int ath6kl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
1081{
1082 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
1083 int ret;
1084
1085 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: changed 0x%x\n", __func__,
1086 changed);
1087
1088 if (!ath6kl_cfg80211_ready(ar))
1089 return -EIO;
1090
1091 if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
1092 ret = ath6kl_wmi_set_rts_cmd(ar->wmi, wiphy->rts_threshold);
1093 if (ret != 0) {
1094 ath6kl_err("ath6kl_wmi_set_rts_cmd failed\n");
1095 return -EIO;
1096 }
1097 }
1098
1099 return 0;
1100}
1101
1102/*
1103 * The type nl80211_tx_power_setting replaces the following
1104 * data type from 2.6.36 onwards
1105*/
1106static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy,
1107 enum nl80211_tx_power_setting type,
1108 int dbm)
1109{
1110 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
1111 u8 ath6kl_dbm;
1112
1113 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x, dbm %d\n", __func__,
1114 type, dbm);
1115
1116 if (!ath6kl_cfg80211_ready(ar))
1117 return -EIO;
1118
1119 switch (type) {
1120 case NL80211_TX_POWER_AUTOMATIC:
1121 return 0;
1122 case NL80211_TX_POWER_LIMITED:
1123 ar->tx_pwr = ath6kl_dbm = dbm;
1124 break;
1125 default:
1126 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x not supported\n",
1127 __func__, type);
1128 return -EOPNOTSUPP;
1129 }
1130
1131 ath6kl_wmi_set_tx_pwr_cmd(ar->wmi, ath6kl_dbm);
1132
1133 return 0;
1134}
1135
1136static int ath6kl_cfg80211_get_txpower(struct wiphy *wiphy, int *dbm)
1137{
1138 struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301139 struct ath6kl_vif *vif = ar->vif;
Kalle Valobdcd8172011-07-18 00:22:30 +03001140
1141 if (!ath6kl_cfg80211_ready(ar))
1142 return -EIO;
1143
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301144 if (test_bit(CONNECTED, &vif->flags)) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001145 ar->tx_pwr = 0;
1146
1147 if (ath6kl_wmi_get_tx_pwr_cmd(ar->wmi) != 0) {
1148 ath6kl_err("ath6kl_wmi_get_tx_pwr_cmd failed\n");
1149 return -EIO;
1150 }
1151
1152 wait_event_interruptible_timeout(ar->event_wq, ar->tx_pwr != 0,
1153 5 * HZ);
1154
1155 if (signal_pending(current)) {
1156 ath6kl_err("target did not respond\n");
1157 return -EINTR;
1158 }
1159 }
1160
1161 *dbm = ar->tx_pwr;
1162 return 0;
1163}
1164
1165static int ath6kl_cfg80211_set_power_mgmt(struct wiphy *wiphy,
1166 struct net_device *dev,
1167 bool pmgmt, int timeout)
1168{
1169 struct ath6kl *ar = ath6kl_priv(dev);
1170 struct wmi_power_mode_cmd mode;
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301171 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001172
1173 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: pmgmt %d, timeout %d\n",
1174 __func__, pmgmt, timeout);
1175
1176 if (!ath6kl_cfg80211_ready(ar))
1177 return -EIO;
1178
1179 if (pmgmt) {
1180 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: max perf\n", __func__);
1181 mode.pwr_mode = REC_POWER;
1182 } else {
1183 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: rec power\n", __func__);
1184 mode.pwr_mode = MAX_PERF_POWER;
1185 }
1186
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301187 if (ath6kl_wmi_powermode_cmd(ar->wmi, vif->fw_vif_idx,
1188 mode.pwr_mode) != 0) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001189 ath6kl_err("wmi_powermode_cmd failed\n");
1190 return -EIO;
1191 }
1192
1193 return 0;
1194}
1195
1196static int ath6kl_cfg80211_change_iface(struct wiphy *wiphy,
1197 struct net_device *ndev,
1198 enum nl80211_iftype type, u32 *flags,
1199 struct vif_params *params)
1200{
1201 struct ath6kl *ar = ath6kl_priv(ndev);
1202 struct wireless_dev *wdev = ar->wdev;
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301203 struct ath6kl_vif *vif = netdev_priv(ndev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001204
1205 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type %u\n", __func__, type);
1206
1207 if (!ath6kl_cfg80211_ready(ar))
1208 return -EIO;
1209
1210 switch (type) {
1211 case NL80211_IFTYPE_STATION:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301212 vif->next_mode = INFRA_NETWORK;
Kalle Valobdcd8172011-07-18 00:22:30 +03001213 break;
1214 case NL80211_IFTYPE_ADHOC:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301215 vif->next_mode = ADHOC_NETWORK;
Kalle Valobdcd8172011-07-18 00:22:30 +03001216 break;
Jouni Malinen6e4604c2011-09-05 17:38:46 +03001217 case NL80211_IFTYPE_AP:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301218 vif->next_mode = AP_NETWORK;
Jouni Malinen6e4604c2011-09-05 17:38:46 +03001219 break;
Jouni Malinen6b5e5d22011-08-30 21:58:05 +03001220 case NL80211_IFTYPE_P2P_CLIENT:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301221 vif->next_mode = INFRA_NETWORK;
Jouni Malinen6b5e5d22011-08-30 21:58:05 +03001222 break;
1223 case NL80211_IFTYPE_P2P_GO:
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301224 vif->next_mode = AP_NETWORK;
Jouni Malinen6b5e5d22011-08-30 21:58:05 +03001225 break;
Kalle Valobdcd8172011-07-18 00:22:30 +03001226 default:
1227 ath6kl_err("invalid interface type %u\n", type);
1228 return -EOPNOTSUPP;
1229 }
1230
1231 wdev->iftype = type;
1232
1233 return 0;
1234}
1235
1236static int ath6kl_cfg80211_join_ibss(struct wiphy *wiphy,
1237 struct net_device *dev,
1238 struct cfg80211_ibss_params *ibss_param)
1239{
1240 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301241 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001242 int status;
1243
1244 if (!ath6kl_cfg80211_ready(ar))
1245 return -EIO;
1246
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301247 vif->ssid_len = ibss_param->ssid_len;
1248 memcpy(vif->ssid, ibss_param->ssid, vif->ssid_len);
Kalle Valobdcd8172011-07-18 00:22:30 +03001249
1250 if (ibss_param->channel)
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +05301251 vif->ch_hint = ibss_param->channel->center_freq;
Kalle Valobdcd8172011-07-18 00:22:30 +03001252
1253 if (ibss_param->channel_fixed) {
1254 /*
1255 * TODO: channel_fixed: The channel should be fixed, do not
1256 * search for IBSSs to join on other channels. Target
1257 * firmware does not support this feature, needs to be
1258 * updated.
1259 */
1260 return -EOPNOTSUPP;
1261 }
1262
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +05301263 memset(vif->req_bssid, 0, sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +03001264 if (ibss_param->bssid && !is_broadcast_ether_addr(ibss_param->bssid))
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +05301265 memcpy(vif->req_bssid, ibss_param->bssid,
1266 sizeof(vif->req_bssid));
Kalle Valobdcd8172011-07-18 00:22:30 +03001267
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301268 ath6kl_set_wpa_version(vif, 0);
Kalle Valobdcd8172011-07-18 00:22:30 +03001269
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301270 status = ath6kl_set_auth_type(vif, NL80211_AUTHTYPE_OPEN_SYSTEM);
Kalle Valobdcd8172011-07-18 00:22:30 +03001271 if (status)
1272 return status;
1273
1274 if (ibss_param->privacy) {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301275 ath6kl_set_cipher(vif, WLAN_CIPHER_SUITE_WEP40, true);
1276 ath6kl_set_cipher(vif, WLAN_CIPHER_SUITE_WEP40, false);
Kalle Valobdcd8172011-07-18 00:22:30 +03001277 } else {
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301278 ath6kl_set_cipher(vif, 0, true);
1279 ath6kl_set_cipher(vif, 0, false);
Kalle Valobdcd8172011-07-18 00:22:30 +03001280 }
1281
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301282 vif->nw_type = vif->next_mode;
Kalle Valobdcd8172011-07-18 00:22:30 +03001283
1284 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1285 "%s: connect called with authmode %d dot11 auth %d"
1286 " PW crypto %d PW crypto len %d GRP crypto %d"
1287 " GRP crypto len %d channel hint %u\n",
1288 __func__,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301289 vif->auth_mode, vif->dot11_auth_mode, vif->prwise_crypto,
1290 vif->prwise_crypto_len, vif->grp_crypto,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +05301291 vif->grp_crypto_len, vif->ch_hint);
Kalle Valobdcd8172011-07-18 00:22:30 +03001292
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301293 status = ath6kl_wmi_connect_cmd(ar->wmi, vif->fw_vif_idx, vif->nw_type,
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301294 vif->dot11_auth_mode, vif->auth_mode,
1295 vif->prwise_crypto,
1296 vif->prwise_crypto_len,
1297 vif->grp_crypto, vif->grp_crypto_len,
1298 vif->ssid_len, vif->ssid,
Vasanthakumar Thiagarajanf74bac52011-10-25 19:34:05 +05301299 vif->req_bssid, vif->ch_hint,
Kalle Valobdcd8172011-07-18 00:22:30 +03001300 ar->connect_ctrl_flags);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301301 set_bit(CONNECT_PEND, &vif->flags);
Kalle Valobdcd8172011-07-18 00:22:30 +03001302
1303 return 0;
1304}
1305
1306static int ath6kl_cfg80211_leave_ibss(struct wiphy *wiphy,
1307 struct net_device *dev)
1308{
1309 struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(dev);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301310 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001311
1312 if (!ath6kl_cfg80211_ready(ar))
1313 return -EIO;
1314
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301315 ath6kl_disconnect(vif);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301316 memset(vif->ssid, 0, sizeof(vif->ssid));
1317 vif->ssid_len = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +03001318
1319 return 0;
1320}
1321
1322static const u32 cipher_suites[] = {
1323 WLAN_CIPHER_SUITE_WEP40,
1324 WLAN_CIPHER_SUITE_WEP104,
1325 WLAN_CIPHER_SUITE_TKIP,
1326 WLAN_CIPHER_SUITE_CCMP,
Jouni Malinen837cb972011-10-11 17:31:57 +03001327 CCKM_KRK_CIPHER_SUITE,
Kalle Valobdcd8172011-07-18 00:22:30 +03001328};
1329
1330static bool is_rate_legacy(s32 rate)
1331{
1332 static const s32 legacy[] = { 1000, 2000, 5500, 11000,
1333 6000, 9000, 12000, 18000, 24000,
1334 36000, 48000, 54000
1335 };
1336 u8 i;
1337
1338 for (i = 0; i < ARRAY_SIZE(legacy); i++)
1339 if (rate == legacy[i])
1340 return true;
1341
1342 return false;
1343}
1344
1345static bool is_rate_ht20(s32 rate, u8 *mcs, bool *sgi)
1346{
1347 static const s32 ht20[] = { 6500, 13000, 19500, 26000, 39000,
1348 52000, 58500, 65000, 72200
1349 };
1350 u8 i;
1351
1352 for (i = 0; i < ARRAY_SIZE(ht20); i++) {
1353 if (rate == ht20[i]) {
1354 if (i == ARRAY_SIZE(ht20) - 1)
1355 /* last rate uses sgi */
1356 *sgi = true;
1357 else
1358 *sgi = false;
1359
1360 *mcs = i;
1361 return true;
1362 }
1363 }
1364 return false;
1365}
1366
1367static bool is_rate_ht40(s32 rate, u8 *mcs, bool *sgi)
1368{
1369 static const s32 ht40[] = { 13500, 27000, 40500, 54000,
1370 81000, 108000, 121500, 135000,
1371 150000
1372 };
1373 u8 i;
1374
1375 for (i = 0; i < ARRAY_SIZE(ht40); i++) {
1376 if (rate == ht40[i]) {
1377 if (i == ARRAY_SIZE(ht40) - 1)
1378 /* last rate uses sgi */
1379 *sgi = true;
1380 else
1381 *sgi = false;
1382
1383 *mcs = i;
1384 return true;
1385 }
1386 }
1387
1388 return false;
1389}
1390
1391static int ath6kl_get_station(struct wiphy *wiphy, struct net_device *dev,
1392 u8 *mac, struct station_info *sinfo)
1393{
1394 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301395 struct ath6kl_vif *vif = netdev_priv(dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001396 long left;
1397 bool sgi;
1398 s32 rate;
1399 int ret;
1400 u8 mcs;
1401
Vasanthakumar Thiagarajan8c8b65e2011-10-25 19:34:04 +05301402 if (memcmp(mac, vif->bssid, ETH_ALEN) != 0)
Kalle Valobdcd8172011-07-18 00:22:30 +03001403 return -ENOENT;
1404
1405 if (down_interruptible(&ar->sem))
1406 return -EBUSY;
1407
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301408 set_bit(STATS_UPDATE_PEND, &vif->flags);
Kalle Valobdcd8172011-07-18 00:22:30 +03001409
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301410 ret = ath6kl_wmi_get_stats_cmd(ar->wmi, vif->fw_vif_idx);
Kalle Valobdcd8172011-07-18 00:22:30 +03001411
1412 if (ret != 0) {
1413 up(&ar->sem);
1414 return -EIO;
1415 }
1416
1417 left = wait_event_interruptible_timeout(ar->event_wq,
1418 !test_bit(STATS_UPDATE_PEND,
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301419 &vif->flags),
Kalle Valobdcd8172011-07-18 00:22:30 +03001420 WMI_TIMEOUT);
1421
1422 up(&ar->sem);
1423
1424 if (left == 0)
1425 return -ETIMEDOUT;
1426 else if (left < 0)
1427 return left;
1428
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301429 if (vif->target_stats.rx_byte) {
1430 sinfo->rx_bytes = vif->target_stats.rx_byte;
Kalle Valobdcd8172011-07-18 00:22:30 +03001431 sinfo->filled |= STATION_INFO_RX_BYTES;
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301432 sinfo->rx_packets = vif->target_stats.rx_pkt;
Kalle Valobdcd8172011-07-18 00:22:30 +03001433 sinfo->filled |= STATION_INFO_RX_PACKETS;
1434 }
1435
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301436 if (vif->target_stats.tx_byte) {
1437 sinfo->tx_bytes = vif->target_stats.tx_byte;
Kalle Valobdcd8172011-07-18 00:22:30 +03001438 sinfo->filled |= STATION_INFO_TX_BYTES;
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301439 sinfo->tx_packets = vif->target_stats.tx_pkt;
Kalle Valobdcd8172011-07-18 00:22:30 +03001440 sinfo->filled |= STATION_INFO_TX_PACKETS;
1441 }
1442
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301443 sinfo->signal = vif->target_stats.cs_rssi;
Kalle Valobdcd8172011-07-18 00:22:30 +03001444 sinfo->filled |= STATION_INFO_SIGNAL;
1445
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +05301446 rate = vif->target_stats.tx_ucast_rate;
Kalle Valobdcd8172011-07-18 00:22:30 +03001447
1448 if (is_rate_legacy(rate)) {
1449 sinfo->txrate.legacy = rate / 100;
1450 } else if (is_rate_ht20(rate, &mcs, &sgi)) {
1451 if (sgi) {
1452 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
1453 sinfo->txrate.mcs = mcs - 1;
1454 } else {
1455 sinfo->txrate.mcs = mcs;
1456 }
1457
1458 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
1459 } else if (is_rate_ht40(rate, &mcs, &sgi)) {
1460 if (sgi) {
1461 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
1462 sinfo->txrate.mcs = mcs - 1;
1463 } else {
1464 sinfo->txrate.mcs = mcs;
1465 }
1466
1467 sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
1468 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
1469 } else {
Kalle Valo9a730832011-09-27 23:33:28 +03001470 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
1471 "invalid rate from stats: %d\n", rate);
1472 ath6kl_debug_war(ar, ATH6KL_WAR_INVALID_RATE);
Kalle Valobdcd8172011-07-18 00:22:30 +03001473 return 0;
1474 }
1475
1476 sinfo->filled |= STATION_INFO_TX_BITRATE;
1477
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301478 if (test_bit(CONNECTED, &vif->flags) &&
1479 test_bit(DTIM_PERIOD_AVAIL, &vif->flags) &&
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301480 vif->nw_type == INFRA_NETWORK) {
Jouni Malinen32c10872011-09-19 19:15:07 +03001481 sinfo->filled |= STATION_INFO_BSS_PARAM;
1482 sinfo->bss_param.flags = 0;
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05301483 sinfo->bss_param.dtim_period = vif->assoc_bss_dtim_period;
1484 sinfo->bss_param.beacon_interval = vif->assoc_bss_beacon_int;
Jouni Malinen32c10872011-09-19 19:15:07 +03001485 }
1486
Kalle Valobdcd8172011-07-18 00:22:30 +03001487 return 0;
1488}
1489
1490static int ath6kl_set_pmksa(struct wiphy *wiphy, struct net_device *netdev,
1491 struct cfg80211_pmksa *pmksa)
1492{
1493 struct ath6kl *ar = ath6kl_priv(netdev);
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301494 struct ath6kl_vif *vif = netdev_priv(netdev);
1495
1496 return ath6kl_wmi_setpmkid_cmd(ar->wmi, vif->fw_vif_idx, pmksa->bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +03001497 pmksa->pmkid, true);
1498}
1499
1500static int ath6kl_del_pmksa(struct wiphy *wiphy, struct net_device *netdev,
1501 struct cfg80211_pmksa *pmksa)
1502{
1503 struct ath6kl *ar = ath6kl_priv(netdev);
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301504 struct ath6kl_vif *vif = netdev_priv(netdev);
1505
1506 return ath6kl_wmi_setpmkid_cmd(ar->wmi, vif->fw_vif_idx, pmksa->bssid,
Kalle Valobdcd8172011-07-18 00:22:30 +03001507 pmksa->pmkid, false);
1508}
1509
1510static int ath6kl_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev)
1511{
1512 struct ath6kl *ar = ath6kl_priv(netdev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301513 struct ath6kl_vif *vif = netdev_priv(netdev);
1514
1515 if (test_bit(CONNECTED, &vif->flags))
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301516 return ath6kl_wmi_setpmkid_cmd(ar->wmi, vif->fw_vif_idx,
1517 vif->bssid, NULL, false);
Kalle Valobdcd8172011-07-18 00:22:30 +03001518 return 0;
1519}
1520
Kalle Valoabcb3442011-07-22 08:26:20 +03001521#ifdef CONFIG_PM
1522static int ar6k_cfg80211_suspend(struct wiphy *wiphy,
1523 struct cfg80211_wowlan *wow)
1524{
1525 struct ath6kl *ar = wiphy_priv(wiphy);
1526
1527 return ath6kl_hif_suspend(ar);
1528}
Chilam Ngaa6cffc2011-10-05 10:12:52 +03001529
1530static int ar6k_cfg80211_resume(struct wiphy *wiphy)
1531{
1532 struct ath6kl *ar = wiphy_priv(wiphy);
1533
1534 return ath6kl_hif_resume(ar);
1535}
Kalle Valoabcb3442011-07-22 08:26:20 +03001536#endif
1537
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001538static int ath6kl_set_channel(struct wiphy *wiphy, struct net_device *dev,
1539 struct ieee80211_channel *chan,
1540 enum nl80211_channel_type channel_type)
1541{
1542 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05301543 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001544
1545 if (!ath6kl_cfg80211_ready(ar))
1546 return -EIO;
1547
1548 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: center_freq=%u hw_value=%u\n",
1549 __func__, chan->center_freq, chan->hw_value);
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05301550 vif->next_chan = chan->center_freq;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001551
1552 return 0;
1553}
1554
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001555static bool ath6kl_is_p2p_ie(const u8 *pos)
1556{
1557 return pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
1558 pos[2] == 0x50 && pos[3] == 0x6f &&
1559 pos[4] == 0x9a && pos[5] == 0x09;
1560}
1561
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301562static int ath6kl_set_ap_probe_resp_ies(struct ath6kl_vif *vif,
1563 const u8 *ies, size_t ies_len)
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001564{
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301565 struct ath6kl *ar = vif->ar;
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001566 const u8 *pos;
1567 u8 *buf = NULL;
1568 size_t len = 0;
1569 int ret;
1570
1571 /*
1572 * Filter out P2P IE(s) since they will be included depending on
1573 * the Probe Request frame in ath6kl_send_go_probe_resp().
1574 */
1575
1576 if (ies && ies_len) {
1577 buf = kmalloc(ies_len, GFP_KERNEL);
1578 if (buf == NULL)
1579 return -ENOMEM;
1580 pos = ies;
1581 while (pos + 1 < ies + ies_len) {
1582 if (pos + 2 + pos[1] > ies + ies_len)
1583 break;
1584 if (!ath6kl_is_p2p_ie(pos)) {
1585 memcpy(buf + len, pos, 2 + pos[1]);
1586 len += 2 + pos[1];
1587 }
1588 pos += 2 + pos[1];
1589 }
1590 }
1591
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301592 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
1593 WMI_FRAME_PROBE_RESP, buf, len);
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001594 kfree(buf);
1595 return ret;
1596}
1597
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001598static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
1599 struct beacon_parameters *info, bool add)
1600{
1601 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301602 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001603 struct ieee80211_mgmt *mgmt;
1604 u8 *ies;
1605 int ies_len;
1606 struct wmi_connect_cmd p;
1607 int res;
1608 int i;
1609
1610 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: add=%d\n", __func__, add);
1611
1612 if (!ath6kl_cfg80211_ready(ar))
1613 return -EIO;
1614
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301615 if (vif->next_mode != AP_NETWORK)
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001616 return -EOPNOTSUPP;
1617
1618 if (info->beacon_ies) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301619 res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
1620 WMI_FRAME_BEACON,
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001621 info->beacon_ies,
1622 info->beacon_ies_len);
1623 if (res)
1624 return res;
1625 }
1626 if (info->proberesp_ies) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301627 res = ath6kl_set_ap_probe_resp_ies(vif, info->proberesp_ies,
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001628 info->proberesp_ies_len);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001629 if (res)
1630 return res;
1631 }
1632 if (info->assocresp_ies) {
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301633 res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
1634 WMI_FRAME_ASSOC_RESP,
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001635 info->assocresp_ies,
1636 info->assocresp_ies_len);
1637 if (res)
1638 return res;
1639 }
1640
1641 if (!add)
1642 return 0;
1643
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001644 ar->ap_mode_bkey.valid = false;
1645
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001646 /* TODO:
1647 * info->interval
1648 * info->dtim_period
1649 */
1650
1651 if (info->head == NULL)
1652 return -EINVAL;
1653 mgmt = (struct ieee80211_mgmt *) info->head;
1654 ies = mgmt->u.beacon.variable;
1655 if (ies > info->head + info->head_len)
1656 return -EINVAL;
1657 ies_len = info->head + info->head_len - ies;
1658
1659 if (info->ssid == NULL)
1660 return -EINVAL;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301661 memcpy(vif->ssid, info->ssid, info->ssid_len);
1662 vif->ssid_len = info->ssid_len;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001663 if (info->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE)
1664 return -EOPNOTSUPP; /* TODO */
1665
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301666 vif->dot11_auth_mode = OPEN_AUTH;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001667
1668 memset(&p, 0, sizeof(p));
1669
1670 for (i = 0; i < info->crypto.n_akm_suites; i++) {
1671 switch (info->crypto.akm_suites[i]) {
1672 case WLAN_AKM_SUITE_8021X:
1673 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_1)
1674 p.auth_mode |= WPA_AUTH;
1675 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_2)
1676 p.auth_mode |= WPA2_AUTH;
1677 break;
1678 case WLAN_AKM_SUITE_PSK:
1679 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_1)
1680 p.auth_mode |= WPA_PSK_AUTH;
1681 if (info->crypto.wpa_versions & NL80211_WPA_VERSION_2)
1682 p.auth_mode |= WPA2_PSK_AUTH;
1683 break;
1684 }
1685 }
1686 if (p.auth_mode == 0)
1687 p.auth_mode = NONE_AUTH;
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301688 vif->auth_mode = p.auth_mode;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001689
1690 for (i = 0; i < info->crypto.n_ciphers_pairwise; i++) {
1691 switch (info->crypto.ciphers_pairwise[i]) {
1692 case WLAN_CIPHER_SUITE_WEP40:
1693 case WLAN_CIPHER_SUITE_WEP104:
1694 p.prwise_crypto_type |= WEP_CRYPT;
1695 break;
1696 case WLAN_CIPHER_SUITE_TKIP:
1697 p.prwise_crypto_type |= TKIP_CRYPT;
1698 break;
1699 case WLAN_CIPHER_SUITE_CCMP:
1700 p.prwise_crypto_type |= AES_CRYPT;
1701 break;
1702 }
1703 }
Edward Lu229ed6b2011-08-30 21:58:07 +03001704 if (p.prwise_crypto_type == 0) {
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001705 p.prwise_crypto_type = NONE_CRYPT;
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301706 ath6kl_set_cipher(vif, 0, true);
Edward Lu229ed6b2011-08-30 21:58:07 +03001707 } else if (info->crypto.n_ciphers_pairwise == 1)
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301708 ath6kl_set_cipher(vif, info->crypto.ciphers_pairwise[0], true);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001709
1710 switch (info->crypto.cipher_group) {
1711 case WLAN_CIPHER_SUITE_WEP40:
1712 case WLAN_CIPHER_SUITE_WEP104:
1713 p.grp_crypto_type = WEP_CRYPT;
1714 break;
1715 case WLAN_CIPHER_SUITE_TKIP:
1716 p.grp_crypto_type = TKIP_CRYPT;
1717 break;
1718 case WLAN_CIPHER_SUITE_CCMP:
1719 p.grp_crypto_type = AES_CRYPT;
1720 break;
1721 default:
1722 p.grp_crypto_type = NONE_CRYPT;
1723 break;
1724 }
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301725 ath6kl_set_cipher(vif, info->crypto.cipher_group, false);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001726
1727 p.nw_type = AP_NETWORK;
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301728 vif->nw_type = vif->next_mode;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001729
Vasanthakumar Thiagarajan34503342011-10-25 19:34:02 +05301730 p.ssid_len = vif->ssid_len;
1731 memcpy(p.ssid, vif->ssid, vif->ssid_len);
1732 p.dot11_auth_mode = vif->dot11_auth_mode;
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05301733 p.ch = cpu_to_le16(vif->next_chan);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001734
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301735 res = ath6kl_wmi_ap_profile_commit(ar->wmi, vif->fw_vif_idx, &p);
Jouni Malinen9a5b1312011-08-30 21:57:52 +03001736 if (res < 0)
1737 return res;
1738
1739 return 0;
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001740}
1741
1742static int ath6kl_add_beacon(struct wiphy *wiphy, struct net_device *dev,
1743 struct beacon_parameters *info)
1744{
1745 return ath6kl_ap_beacon(wiphy, dev, info, true);
1746}
1747
1748static int ath6kl_set_beacon(struct wiphy *wiphy, struct net_device *dev,
1749 struct beacon_parameters *info)
1750{
1751 return ath6kl_ap_beacon(wiphy, dev, info, false);
1752}
1753
1754static int ath6kl_del_beacon(struct wiphy *wiphy, struct net_device *dev)
1755{
1756 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301757 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001758
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301759 if (vif->nw_type != AP_NETWORK)
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001760 return -EOPNOTSUPP;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301761 if (!test_bit(CONNECTED, &vif->flags))
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001762 return -ENOTCONN;
1763
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301764 ath6kl_wmi_disconnect_cmd(ar->wmi, vif->fw_vif_idx);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301765 clear_bit(CONNECTED, &vif->flags);
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001766
1767 return 0;
1768}
1769
Jouni Malinen23875132011-08-30 21:57:53 +03001770static int ath6kl_change_station(struct wiphy *wiphy, struct net_device *dev,
1771 u8 *mac, struct station_parameters *params)
1772{
1773 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301774 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen23875132011-08-30 21:57:53 +03001775
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301776 if (vif->nw_type != AP_NETWORK)
Jouni Malinen23875132011-08-30 21:57:53 +03001777 return -EOPNOTSUPP;
1778
1779 /* Use this only for authorizing/unauthorizing a station */
1780 if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)))
1781 return -EOPNOTSUPP;
1782
1783 if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED))
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301784 return ath6kl_wmi_ap_set_mlme(ar->wmi, vif->fw_vif_idx,
1785 WMI_AP_MLME_AUTHORIZE, mac, 0);
1786 return ath6kl_wmi_ap_set_mlme(ar->wmi, vif->fw_vif_idx,
1787 WMI_AP_MLME_UNAUTHORIZE, mac, 0);
Jouni Malinen23875132011-08-30 21:57:53 +03001788}
1789
Jouni Malinen63fa1e02011-08-30 21:57:55 +03001790static int ath6kl_remain_on_channel(struct wiphy *wiphy,
1791 struct net_device *dev,
1792 struct ieee80211_channel *chan,
1793 enum nl80211_channel_type channel_type,
1794 unsigned int duration,
1795 u64 *cookie)
1796{
1797 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301798 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen63fa1e02011-08-30 21:57:55 +03001799
1800 /* TODO: if already pending or ongoing remain-on-channel,
1801 * return -EBUSY */
1802 *cookie = 1; /* only a single pending request is supported */
1803
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301804 return ath6kl_wmi_remain_on_chnl_cmd(ar->wmi, vif->fw_vif_idx,
1805 chan->center_freq, duration);
Jouni Malinen63fa1e02011-08-30 21:57:55 +03001806}
1807
1808static int ath6kl_cancel_remain_on_channel(struct wiphy *wiphy,
1809 struct net_device *dev,
1810 u64 cookie)
1811{
1812 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301813 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen63fa1e02011-08-30 21:57:55 +03001814
1815 if (cookie != 1)
1816 return -ENOENT;
1817
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301818 return ath6kl_wmi_cancel_remain_on_chnl_cmd(ar->wmi, vif->fw_vif_idx);
Jouni Malinen63fa1e02011-08-30 21:57:55 +03001819}
1820
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301821static int ath6kl_send_go_probe_resp(struct ath6kl_vif *vif,
1822 const u8 *buf, size_t len,
1823 unsigned int freq)
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001824{
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301825 struct ath6kl *ar = vif->ar;
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001826 const u8 *pos;
1827 u8 *p2p;
1828 int p2p_len;
1829 int ret;
1830 const struct ieee80211_mgmt *mgmt;
1831
1832 mgmt = (const struct ieee80211_mgmt *) buf;
1833
1834 /* Include P2P IE(s) from the frame generated in user space. */
1835
1836 p2p = kmalloc(len, GFP_KERNEL);
1837 if (p2p == NULL)
1838 return -ENOMEM;
1839 p2p_len = 0;
1840
1841 pos = mgmt->u.probe_resp.variable;
1842 while (pos + 1 < buf + len) {
1843 if (pos + 2 + pos[1] > buf + len)
1844 break;
1845 if (ath6kl_is_p2p_ie(pos)) {
1846 memcpy(p2p + p2p_len, pos, 2 + pos[1]);
1847 p2p_len += 2 + pos[1];
1848 }
1849 pos += 2 + pos[1];
1850 }
1851
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301852 ret = ath6kl_wmi_send_probe_response_cmd(ar->wmi, vif->fw_vif_idx, freq,
1853 mgmt->da, p2p, p2p_len);
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001854 kfree(p2p);
1855 return ret;
1856}
1857
Jouni Malinen8a6c80602011-08-30 21:57:56 +03001858static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
1859 struct ieee80211_channel *chan, bool offchan,
1860 enum nl80211_channel_type channel_type,
1861 bool channel_type_valid, unsigned int wait,
Johannes Berge247bd902011-11-04 11:18:21 +01001862 const u8 *buf, size_t len, bool no_cck,
1863 bool dont_wait_for_ack, u64 *cookie)
Jouni Malinen8a6c80602011-08-30 21:57:56 +03001864{
1865 struct ath6kl *ar = ath6kl_priv(dev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05301866 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinen8a6c80602011-08-30 21:57:56 +03001867 u32 id;
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001868 const struct ieee80211_mgmt *mgmt;
1869
1870 mgmt = (const struct ieee80211_mgmt *) buf;
1871 if (buf + len >= mgmt->u.probe_resp.variable &&
Vasanthakumar Thiagarajanf5938f22011-10-25 19:34:03 +05301872 vif->nw_type == AP_NETWORK && test_bit(CONNECTED, &vif->flags) &&
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001873 ieee80211_is_probe_resp(mgmt->frame_control)) {
1874 /*
1875 * Send Probe Response frame in AP mode using a separate WMI
1876 * command to allow the target to fill in the generic IEs.
1877 */
1878 *cookie = 0; /* TX status not supported */
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301879 return ath6kl_send_go_probe_resp(vif, buf, len,
Jouni Malinen8bdfbf42011-08-30 21:58:09 +03001880 chan->center_freq);
1881 }
Jouni Malinen8a6c80602011-08-30 21:57:56 +03001882
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05301883 id = vif->send_action_id++;
Jouni Malinen8a6c80602011-08-30 21:57:56 +03001884 if (id == 0) {
1885 /*
1886 * 0 is a reserved value in the WMI command and shall not be
1887 * used for the command.
1888 */
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05301889 id = vif->send_action_id++;
Jouni Malinen8a6c80602011-08-30 21:57:56 +03001890 }
1891
1892 *cookie = id;
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301893 return ath6kl_wmi_send_action_cmd(ar->wmi, vif->fw_vif_idx, id,
1894 chan->center_freq, wait,
Jouni Malinen8a6c80602011-08-30 21:57:56 +03001895 buf, len);
1896}
1897
Jouni Malinenae32c302011-08-30 21:58:01 +03001898static void ath6kl_mgmt_frame_register(struct wiphy *wiphy,
1899 struct net_device *dev,
1900 u16 frame_type, bool reg)
1901{
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05301902 struct ath6kl_vif *vif = netdev_priv(dev);
Jouni Malinenae32c302011-08-30 21:58:01 +03001903
1904 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: frame_type=0x%x reg=%d\n",
1905 __func__, frame_type, reg);
1906 if (frame_type == IEEE80211_STYPE_PROBE_REQ) {
1907 /*
1908 * Note: This notification callback is not allowed to sleep, so
1909 * we cannot send WMI_PROBE_REQ_REPORT_CMD here. Instead, we
1910 * hardcode target to report Probe Request frames all the time.
1911 */
Vasanthakumar Thiagarajancf5333d2011-10-25 19:34:10 +05301912 vif->probe_req_report = reg;
Jouni Malinenae32c302011-08-30 21:58:01 +03001913 }
1914}
1915
Jouni Malinenf80574a2011-08-30 21:58:04 +03001916static const struct ieee80211_txrx_stypes
1917ath6kl_mgmt_stypes[NUM_NL80211_IFTYPES] = {
1918 [NL80211_IFTYPE_STATION] = {
1919 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1920 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
1921 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1922 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
1923 },
1924 [NL80211_IFTYPE_P2P_CLIENT] = {
1925 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1926 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
1927 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1928 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
1929 },
1930 [NL80211_IFTYPE_P2P_GO] = {
1931 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1932 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
1933 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1934 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
1935 },
1936};
1937
Kalle Valobdcd8172011-07-18 00:22:30 +03001938static struct cfg80211_ops ath6kl_cfg80211_ops = {
1939 .change_virtual_intf = ath6kl_cfg80211_change_iface,
1940 .scan = ath6kl_cfg80211_scan,
1941 .connect = ath6kl_cfg80211_connect,
1942 .disconnect = ath6kl_cfg80211_disconnect,
1943 .add_key = ath6kl_cfg80211_add_key,
1944 .get_key = ath6kl_cfg80211_get_key,
1945 .del_key = ath6kl_cfg80211_del_key,
1946 .set_default_key = ath6kl_cfg80211_set_default_key,
1947 .set_wiphy_params = ath6kl_cfg80211_set_wiphy_params,
1948 .set_tx_power = ath6kl_cfg80211_set_txpower,
1949 .get_tx_power = ath6kl_cfg80211_get_txpower,
1950 .set_power_mgmt = ath6kl_cfg80211_set_power_mgmt,
1951 .join_ibss = ath6kl_cfg80211_join_ibss,
1952 .leave_ibss = ath6kl_cfg80211_leave_ibss,
1953 .get_station = ath6kl_get_station,
1954 .set_pmksa = ath6kl_set_pmksa,
1955 .del_pmksa = ath6kl_del_pmksa,
1956 .flush_pmksa = ath6kl_flush_pmksa,
Kalle Valo003353b0d2011-09-01 10:14:21 +03001957 CFG80211_TESTMODE_CMD(ath6kl_tm_cmd)
Kalle Valoabcb3442011-07-22 08:26:20 +03001958#ifdef CONFIG_PM
1959 .suspend = ar6k_cfg80211_suspend,
Chilam Ngaa6cffc2011-10-05 10:12:52 +03001960 .resume = ar6k_cfg80211_resume,
Kalle Valoabcb3442011-07-22 08:26:20 +03001961#endif
Jouni Malinen6a7c9ba2011-08-30 21:57:50 +03001962 .set_channel = ath6kl_set_channel,
1963 .add_beacon = ath6kl_add_beacon,
1964 .set_beacon = ath6kl_set_beacon,
1965 .del_beacon = ath6kl_del_beacon,
Jouni Malinen23875132011-08-30 21:57:53 +03001966 .change_station = ath6kl_change_station,
Jouni Malinen63fa1e02011-08-30 21:57:55 +03001967 .remain_on_channel = ath6kl_remain_on_channel,
1968 .cancel_remain_on_channel = ath6kl_cancel_remain_on_channel,
Jouni Malinen8a6c80602011-08-30 21:57:56 +03001969 .mgmt_tx = ath6kl_mgmt_tx,
Jouni Malinenae32c302011-08-30 21:58:01 +03001970 .mgmt_frame_register = ath6kl_mgmt_frame_register,
Kalle Valobdcd8172011-07-18 00:22:30 +03001971};
1972
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05301973struct ath6kl *ath6kl_core_alloc(struct device *dev)
Kalle Valobdcd8172011-07-18 00:22:30 +03001974{
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03001975 struct ath6kl *ar;
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05301976 struct wiphy *wiphy;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05301977 u8 ctr;
Kalle Valobdcd8172011-07-18 00:22:30 +03001978
1979 /* create a new wiphy for use with cfg80211 */
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05301980 wiphy = wiphy_new(&ath6kl_cfg80211_ops, sizeof(struct ath6kl));
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05301981
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05301982 if (!wiphy) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001983 ath6kl_err("couldn't allocate wiphy device\n");
Kalle Valobdcd8172011-07-18 00:22:30 +03001984 return NULL;
1985 }
1986
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05301987 ar = wiphy_priv(wiphy);
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03001988 ar->p2p = !!ath6kl_p2p;
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05301989 ar->wiphy = wiphy;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05301990 ar->dev = dev;
1991
1992 spin_lock_init(&ar->lock);
1993 spin_lock_init(&ar->mcastpsq_lock);
1994
1995 init_waitqueue_head(&ar->event_wq);
1996 sema_init(&ar->sem, 1);
1997
1998 INIT_LIST_HEAD(&ar->amsdu_rx_buffer_queue);
1999
2000 clear_bit(WMI_ENABLED, &ar->flag);
2001 clear_bit(SKIP_SCAN, &ar->flag);
2002 clear_bit(DESTROY_IN_PROGRESS, &ar->flag);
2003
2004 ar->listen_intvl_t = A_DEFAULT_LISTEN_INTERVAL;
2005 ar->listen_intvl_b = 0;
2006 ar->tx_pwr = 0;
2007
2008 ar->intra_bss = 1;
2009 memset(&ar->sc_params, 0, sizeof(ar->sc_params));
2010 ar->sc_params.short_scan_ratio = WMI_SHORTSCANRATIO_DEFAULT;
2011 ar->sc_params.scan_ctrl_flags = DEFAULT_SCAN_CTRL_FLAGS;
2012 ar->lrssi_roam_threshold = DEF_LRSSI_ROAM_THRESHOLD;
2013
2014 memset((u8 *)ar->sta_list, 0,
2015 AP_MAX_NUM_STA * sizeof(struct ath6kl_sta));
2016
2017 /* Init the PS queues */
2018 for (ctr = 0; ctr < AP_MAX_NUM_STA; ctr++) {
2019 spin_lock_init(&ar->sta_list[ctr].psq_lock);
2020 skb_queue_head_init(&ar->sta_list[ctr].psq);
2021 }
2022
2023 skb_queue_head_init(&ar->mcastpsq);
2024
2025 memcpy(ar->ap_country_code, DEF_AP_COUNTRY_CODE, 3);
2026
2027 return ar;
2028}
2029
2030int ath6kl_register_ieee80211_hw(struct ath6kl *ar)
2031{
2032 struct wiphy *wiphy = ar->wiphy;
2033 int ret;
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03002034
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302035 wiphy->mgmt_stypes = ath6kl_mgmt_stypes;
Jouni Malinenf80574a2011-08-30 21:58:04 +03002036
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302037 wiphy->max_remain_on_channel_duration = 5000;
Jouni Malinen63fa1e02011-08-30 21:57:55 +03002038
Kalle Valobdcd8172011-07-18 00:22:30 +03002039 /* set device pointer for wiphy */
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302040 set_wiphy_dev(wiphy, ar->dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03002041
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302042 wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302043 BIT(NL80211_IFTYPE_ADHOC) |
2044 BIT(NL80211_IFTYPE_AP);
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03002045 if (ar->p2p) {
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302046 wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_GO) |
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302047 BIT(NL80211_IFTYPE_P2P_CLIENT);
Jouni Malinen6bbc7c32011-09-05 17:38:47 +03002048 }
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302049
Kalle Valobdcd8172011-07-18 00:22:30 +03002050 /* max num of ssids that can be probed during scanning */
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302051 wiphy->max_scan_ssids = MAX_PROBED_SSID_INDEX;
2052 wiphy->max_scan_ie_len = 1000; /* FIX: what is correct limit? */
2053 wiphy->bands[IEEE80211_BAND_2GHZ] = &ath6kl_band_2ghz;
2054 wiphy->bands[IEEE80211_BAND_5GHZ] = &ath6kl_band_5ghz;
2055 wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
Kalle Valobdcd8172011-07-18 00:22:30 +03002056
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302057 wiphy->cipher_suites = cipher_suites;
2058 wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
Kalle Valobdcd8172011-07-18 00:22:30 +03002059
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302060 ret = wiphy_register(wiphy);
Kalle Valobdcd8172011-07-18 00:22:30 +03002061 if (ret < 0) {
2062 ath6kl_err("couldn't register wiphy device\n");
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302063 return ret;
Kalle Valobdcd8172011-07-18 00:22:30 +03002064 }
2065
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302066 return 0;
Kalle Valobdcd8172011-07-18 00:22:30 +03002067}
2068
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302069static int ath6kl_init_if_data(struct ath6kl_vif *vif)
Kalle Valobdcd8172011-07-18 00:22:30 +03002070{
Vasanthakumar Thiagarajan2132c692011-10-25 19:34:07 +05302071 vif->aggr_cntxt = aggr_init(vif->ndev);
2072 if (!vif->aggr_cntxt) {
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302073 ath6kl_err("failed to initialize aggr\n");
2074 return -ENOMEM;
2075 }
Kalle Valobdcd8172011-07-18 00:22:30 +03002076
Vasanthakumar Thiagarajande3ad712011-10-25 19:34:08 +05302077 setup_timer(&vif->disconnect_timer, disconnect_timer_handler,
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302078 (unsigned long) vif->ndev);
Vasanthakumar Thiagarajande3ad712011-10-25 19:34:08 +05302079 set_bit(WMM_ENABLED, &vif->flags);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302080
2081 return 0;
2082}
2083
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302084void ath6kl_deinit_if_data(struct ath6kl_vif *vif)
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302085{
Vasanthakumar Thiagarajan2132c692011-10-25 19:34:07 +05302086 aggr_module_destroy(vif->aggr_cntxt);
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302087
Vasanthakumar Thiagarajan2132c692011-10-25 19:34:07 +05302088 vif->aggr_cntxt = NULL;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302089
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302090 if (test_bit(NETDEV_REGISTERED, &vif->flags)) {
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302091 unregister_netdev(vif->ndev);
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302092 clear_bit(NETDEV_REGISTERED, &vif->flags);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302093 }
2094
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302095 free_netdev(vif->ndev);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302096}
2097
2098struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name,
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302099 enum nl80211_iftype type, u8 fw_vif_idx)
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302100{
2101 struct net_device *ndev;
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302102 struct ath6kl_vif *vif;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302103
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302104 ndev = alloc_netdev(sizeof(*vif), "wlan%d", ether_setup);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302105 if (!ndev)
2106 return NULL;
2107
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302108 vif = netdev_priv(ndev);
2109 ndev->ieee80211_ptr = &vif->wdev;
2110 vif->wdev.wiphy = ar->wiphy;
2111 vif->ar = ar;
2112 ar->vif = vif;
2113 vif->ndev = ndev;
2114 SET_NETDEV_DEV(ndev, wiphy_dev(vif->wdev.wiphy));
2115 vif->wdev.netdev = ndev;
2116 vif->wdev.iftype = type;
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05302117 vif->fw_vif_idx = fw_vif_idx;
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302118 ar->wdev = &vif->wdev;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302119
2120 init_netdev(ndev);
2121
Vasanthakumar Thiagarajane29f25f2011-10-25 19:34:15 +05302122 ath6kl_init_control_info(vif);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302123
2124 /* TODO: Pass interface specific pointer instead of ar */
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302125 if (ath6kl_init_if_data(vif))
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302126 goto err;
2127
2128 if (register_netdev(ndev))
2129 goto err;
2130
Vasanthakumar Thiagarajan14ee6f62011-10-25 19:34:09 +05302131 vif->sme_state = SME_DISCONNECTED;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302132 set_bit(WLAN_ENABLED, &vif->flags);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302133 ar->wlan_pwr_state = WLAN_POWER_STATE_ON;
Vasanthakumar Thiagarajan59c98442011-10-25 19:34:01 +05302134 set_bit(NETDEV_REGISTERED, &vif->flags);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302135
2136 return ndev;
2137
2138err:
Vasanthakumar Thiagarajan108438b2011-10-25 19:34:00 +05302139 ath6kl_deinit_if_data(vif);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05302140
2141 return NULL;
2142}
2143
2144void ath6kl_deinit_ieee80211_hw(struct ath6kl *ar)
2145{
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05302146 wiphy_unregister(ar->wiphy);
2147 wiphy_free(ar->wiphy);
Kalle Valobdcd8172011-07-18 00:22:30 +03002148}