]>
Commit | Line | Data |
---|---|---|
bdcd8170 KV |
1 | /* |
2 | * Copyright (c) 2004-2011 Atheros Communications Inc. | |
1b2df407 | 3 | * Copyright (c) 2011-2012 Qualcomm Atheros, Inc. |
bdcd8170 KV |
4 | * |
5 | * Permission to use, copy, modify, and/or distribute this software for any | |
6 | * purpose with or without fee is hereby granted, provided that the above | |
7 | * copyright notice and this permission notice appear in all copies. | |
8 | * | |
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
13 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
14 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
16 | */ | |
17 | ||
516304b0 JP |
18 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
19 | ||
bdcd8170 KV |
20 | #include "core.h" |
21 | #include "hif-ops.h" | |
22 | #include "cfg80211.h" | |
23 | #include "target.h" | |
24 | #include "debug.h" | |
25 | ||
6765d0aa | 26 | struct ath6kl_sta *ath6kl_find_sta(struct ath6kl_vif *vif, u8 *node_addr) |
bdcd8170 | 27 | { |
6765d0aa | 28 | struct ath6kl *ar = vif->ar; |
bdcd8170 KV |
29 | struct ath6kl_sta *conn = NULL; |
30 | u8 i, max_conn; | |
31 | ||
9d0e2f07 MSS |
32 | if (is_zero_ether_addr(node_addr)) |
33 | return NULL; | |
34 | ||
f5938f24 | 35 | max_conn = (vif->nw_type == AP_NETWORK) ? AP_MAX_NUM_STA : 0; |
bdcd8170 KV |
36 | |
37 | for (i = 0; i < max_conn; i++) { | |
38 | if (memcmp(node_addr, ar->sta_list[i].mac, ETH_ALEN) == 0) { | |
39 | conn = &ar->sta_list[i]; | |
40 | break; | |
41 | } | |
42 | } | |
43 | ||
44 | return conn; | |
45 | } | |
46 | ||
47 | struct ath6kl_sta *ath6kl_find_sta_by_aid(struct ath6kl *ar, u8 aid) | |
48 | { | |
49 | struct ath6kl_sta *conn = NULL; | |
50 | u8 ctr; | |
51 | ||
52 | for (ctr = 0; ctr < AP_MAX_NUM_STA; ctr++) { | |
53 | if (ar->sta_list[ctr].aid == aid) { | |
54 | conn = &ar->sta_list[ctr]; | |
55 | break; | |
56 | } | |
57 | } | |
58 | return conn; | |
59 | } | |
60 | ||
17741c8d VT |
61 | static void ath6kl_add_new_sta(struct ath6kl_vif *vif, u8 *mac, u16 aid, |
62 | u8 *wpaie, size_t ielen, u8 keymgmt, | |
63 | u8 ucipher, u8 auth, u8 apsd_info) | |
bdcd8170 | 64 | { |
17741c8d | 65 | struct ath6kl *ar = vif->ar; |
bdcd8170 KV |
66 | struct ath6kl_sta *sta; |
67 | u8 free_slot; | |
68 | ||
69 | free_slot = aid - 1; | |
70 | ||
71 | sta = &ar->sta_list[free_slot]; | |
72 | memcpy(sta->mac, mac, ETH_ALEN); | |
3c774bba JM |
73 | if (ielen <= ATH6KL_MAX_IE) |
74 | memcpy(sta->wpa_ie, wpaie, ielen); | |
bdcd8170 KV |
75 | sta->aid = aid; |
76 | sta->keymgmt = keymgmt; | |
77 | sta->ucipher = ucipher; | |
78 | sta->auth = auth; | |
c1762a3f | 79 | sta->apsd_info = apsd_info; |
bdcd8170 KV |
80 | |
81 | ar->sta_list_index = ar->sta_list_index | (1 << free_slot); | |
82 | ar->ap_stats.sta[free_slot].aid = cpu_to_le32(aid); | |
c8651541 | 83 | aggr_conn_init(vif, vif->aggr_cntxt, sta->aggr_conn); |
bdcd8170 KV |
84 | } |
85 | ||
86 | static void ath6kl_sta_cleanup(struct ath6kl *ar, u8 i) | |
87 | { | |
88 | struct ath6kl_sta *sta = &ar->sta_list[i]; | |
d0ff7383 | 89 | struct ath6kl_mgmt_buff *entry, *tmp; |
bdcd8170 KV |
90 | |
91 | /* empty the queued pkts in the PS queue if any */ | |
92 | spin_lock_bh(&sta->psq_lock); | |
93 | skb_queue_purge(&sta->psq); | |
c1762a3f | 94 | skb_queue_purge(&sta->apsdq); |
d0ff7383 NG |
95 | |
96 | if (sta->mgmt_psq_len != 0) { | |
97 | list_for_each_entry_safe(entry, tmp, &sta->mgmt_psq, list) { | |
98 | kfree(entry); | |
99 | } | |
100 | INIT_LIST_HEAD(&sta->mgmt_psq); | |
101 | sta->mgmt_psq_len = 0; | |
102 | } | |
103 | ||
bdcd8170 KV |
104 | spin_unlock_bh(&sta->psq_lock); |
105 | ||
106 | memset(&ar->ap_stats.sta[sta->aid - 1], 0, | |
107 | sizeof(struct wmi_per_sta_stat)); | |
93803b33 | 108 | eth_zero_addr(sta->mac); |
bdcd8170 KV |
109 | memset(sta->wpa_ie, 0, ATH6KL_MAX_IE); |
110 | sta->aid = 0; | |
111 | sta->sta_flags = 0; | |
112 | ||
113 | ar->sta_list_index = ar->sta_list_index & ~(1 << i); | |
1d2a4456 | 114 | aggr_reset_state(sta->aggr_conn); |
bdcd8170 KV |
115 | } |
116 | ||
117 | static u8 ath6kl_remove_sta(struct ath6kl *ar, u8 *mac, u16 reason) | |
118 | { | |
119 | u8 i, removed = 0; | |
120 | ||
121 | if (is_zero_ether_addr(mac)) | |
122 | return removed; | |
123 | ||
124 | if (is_broadcast_ether_addr(mac)) { | |
125 | ath6kl_dbg(ATH6KL_DBG_TRC, "deleting all station\n"); | |
126 | ||
127 | for (i = 0; i < AP_MAX_NUM_STA; i++) { | |
128 | if (!is_zero_ether_addr(ar->sta_list[i].mac)) { | |
129 | ath6kl_sta_cleanup(ar, i); | |
130 | removed = 1; | |
131 | } | |
132 | } | |
133 | } else { | |
134 | for (i = 0; i < AP_MAX_NUM_STA; i++) { | |
135 | if (memcmp(ar->sta_list[i].mac, mac, ETH_ALEN) == 0) { | |
136 | ath6kl_dbg(ATH6KL_DBG_TRC, | |
137 | "deleting station %pM aid=%d reason=%d\n", | |
138 | mac, ar->sta_list[i].aid, reason); | |
139 | ath6kl_sta_cleanup(ar, i); | |
140 | removed = 1; | |
141 | break; | |
142 | } | |
143 | } | |
144 | } | |
145 | ||
146 | return removed; | |
147 | } | |
148 | ||
149 | enum htc_endpoint_id ath6kl_ac2_endpoint_id(void *devt, u8 ac) | |
150 | { | |
151 | struct ath6kl *ar = devt; | |
152 | return ar->ac2ep_map[ac]; | |
153 | } | |
154 | ||
155 | struct ath6kl_cookie *ath6kl_alloc_cookie(struct ath6kl *ar) | |
156 | { | |
157 | struct ath6kl_cookie *cookie; | |
158 | ||
159 | cookie = ar->cookie_list; | |
160 | if (cookie != NULL) { | |
161 | ar->cookie_list = cookie->arc_list_next; | |
162 | ar->cookie_count--; | |
163 | } | |
164 | ||
165 | return cookie; | |
166 | } | |
167 | ||
168 | void ath6kl_cookie_init(struct ath6kl *ar) | |
169 | { | |
170 | u32 i; | |
171 | ||
172 | ar->cookie_list = NULL; | |
173 | ar->cookie_count = 0; | |
174 | ||
175 | memset(ar->cookie_mem, 0, sizeof(ar->cookie_mem)); | |
176 | ||
177 | for (i = 0; i < MAX_COOKIE_NUM; i++) | |
178 | ath6kl_free_cookie(ar, &ar->cookie_mem[i]); | |
179 | } | |
180 | ||
181 | void ath6kl_cookie_cleanup(struct ath6kl *ar) | |
182 | { | |
183 | ar->cookie_list = NULL; | |
184 | ar->cookie_count = 0; | |
185 | } | |
186 | ||
187 | void ath6kl_free_cookie(struct ath6kl *ar, struct ath6kl_cookie *cookie) | |
188 | { | |
189 | /* Insert first */ | |
190 | ||
191 | if (!ar || !cookie) | |
192 | return; | |
193 | ||
194 | cookie->arc_list_next = ar->cookie_list; | |
195 | ar->cookie_list = cookie; | |
196 | ar->cookie_count++; | |
197 | } | |
198 | ||
bdcd8170 | 199 | /* |
addb44be KV |
200 | * Read from the hardware through its diagnostic window. No cooperation |
201 | * from the firmware is required for this. | |
bdcd8170 | 202 | */ |
addb44be | 203 | int ath6kl_diag_read32(struct ath6kl *ar, u32 address, u32 *value) |
bdcd8170 | 204 | { |
addb44be | 205 | int ret; |
bdcd8170 | 206 | |
c7111495 | 207 | ret = ath6kl_hif_diag_read32(ar, address, value); |
addb44be KV |
208 | if (ret) { |
209 | ath6kl_warn("failed to read32 through diagnose window: %d\n", | |
210 | ret); | |
211 | return ret; | |
bdcd8170 KV |
212 | } |
213 | ||
addb44be | 214 | return 0; |
bdcd8170 KV |
215 | } |
216 | ||
bdcd8170 KV |
217 | /* |
218 | * Write to the ATH6KL through its diagnostic window. No cooperation from | |
219 | * the Target is required for this. | |
220 | */ | |
f9ea0753 | 221 | int ath6kl_diag_write32(struct ath6kl *ar, u32 address, __le32 value) |
bdcd8170 | 222 | { |
addb44be | 223 | int ret; |
bdcd8170 | 224 | |
c7111495 KV |
225 | ret = ath6kl_hif_diag_write32(ar, address, value); |
226 | ||
addb44be | 227 | if (ret) { |
10d49878 | 228 | ath6kl_err("failed to write 0x%x during diagnose window to 0x%x\n", |
addb44be KV |
229 | address, value); |
230 | return ret; | |
bdcd8170 KV |
231 | } |
232 | ||
c7111495 | 233 | return 0; |
bdcd8170 KV |
234 | } |
235 | ||
addb44be | 236 | int ath6kl_diag_read(struct ath6kl *ar, u32 address, void *data, u32 length) |
bdcd8170 | 237 | { |
addb44be KV |
238 | u32 count, *buf = data; |
239 | int ret; | |
bdcd8170 | 240 | |
addb44be KV |
241 | if (WARN_ON(length % 4)) |
242 | return -EINVAL; | |
243 | ||
244 | for (count = 0; count < length / 4; count++, address += 4) { | |
245 | ret = ath6kl_diag_read32(ar, address, &buf[count]); | |
246 | if (ret) | |
247 | return ret; | |
bdcd8170 KV |
248 | } |
249 | ||
addb44be KV |
250 | return 0; |
251 | } | |
252 | ||
253 | int ath6kl_diag_write(struct ath6kl *ar, u32 address, void *data, u32 length) | |
254 | { | |
f9ea0753 VT |
255 | u32 count; |
256 | __le32 *buf = data; | |
addb44be KV |
257 | int ret; |
258 | ||
259 | if (WARN_ON(length % 4)) | |
260 | return -EINVAL; | |
261 | ||
262 | for (count = 0; count < length / 4; count++, address += 4) { | |
263 | ret = ath6kl_diag_write32(ar, address, buf[count]); | |
264 | if (ret) | |
265 | return ret; | |
266 | } | |
267 | ||
268 | return 0; | |
bdcd8170 KV |
269 | } |
270 | ||
bc07ddb2 KV |
271 | int ath6kl_read_fwlogs(struct ath6kl *ar) |
272 | { | |
273 | struct ath6kl_dbglog_hdr debug_hdr; | |
274 | struct ath6kl_dbglog_buf debug_buf; | |
275 | u32 address, length, dropped, firstbuf, debug_hdr_addr; | |
e80ec84d | 276 | int ret, loop; |
bc07ddb2 KV |
277 | u8 *buf; |
278 | ||
279 | buf = kmalloc(ATH6KL_FWLOG_PAYLOAD_SIZE, GFP_KERNEL); | |
280 | if (!buf) | |
281 | return -ENOMEM; | |
282 | ||
283 | address = TARG_VTOP(ar->target_type, | |
284 | ath6kl_get_hi_item_addr(ar, | |
285 | HI_ITEM(hi_dbglog_hdr))); | |
286 | ||
287 | ret = ath6kl_diag_read32(ar, address, &debug_hdr_addr); | |
288 | if (ret) | |
289 | goto out; | |
290 | ||
291 | /* Get the contents of the ring buffer */ | |
292 | if (debug_hdr_addr == 0) { | |
293 | ath6kl_warn("Invalid address for debug_hdr_addr\n"); | |
294 | ret = -EINVAL; | |
295 | goto out; | |
296 | } | |
297 | ||
298 | address = TARG_VTOP(ar->target_type, debug_hdr_addr); | |
4aca81bf PP |
299 | ret = ath6kl_diag_read(ar, address, &debug_hdr, sizeof(debug_hdr)); |
300 | if (ret) | |
301 | goto out; | |
bc07ddb2 KV |
302 | |
303 | address = TARG_VTOP(ar->target_type, | |
304 | le32_to_cpu(debug_hdr.dbuf_addr)); | |
305 | firstbuf = address; | |
306 | dropped = le32_to_cpu(debug_hdr.dropped); | |
4aca81bf PP |
307 | ret = ath6kl_diag_read(ar, address, &debug_buf, sizeof(debug_buf)); |
308 | if (ret) | |
309 | goto out; | |
bc07ddb2 KV |
310 | |
311 | loop = 100; | |
312 | ||
313 | do { | |
314 | address = TARG_VTOP(ar->target_type, | |
315 | le32_to_cpu(debug_buf.buffer_addr)); | |
316 | length = le32_to_cpu(debug_buf.length); | |
317 | ||
318 | if (length != 0 && (le32_to_cpu(debug_buf.length) <= | |
319 | le32_to_cpu(debug_buf.bufsize))) { | |
320 | length = ALIGN(length, 4); | |
321 | ||
322 | ret = ath6kl_diag_read(ar, address, | |
323 | buf, length); | |
324 | if (ret) | |
325 | goto out; | |
326 | ||
327 | ath6kl_debug_fwlog_event(ar, buf, length); | |
328 | } | |
329 | ||
330 | address = TARG_VTOP(ar->target_type, | |
331 | le32_to_cpu(debug_buf.next)); | |
4aca81bf PP |
332 | ret = ath6kl_diag_read(ar, address, &debug_buf, |
333 | sizeof(debug_buf)); | |
bc07ddb2 KV |
334 | if (ret) |
335 | goto out; | |
336 | ||
337 | loop--; | |
338 | ||
339 | if (WARN_ON(loop == 0)) { | |
340 | ret = -ETIMEDOUT; | |
341 | goto out; | |
342 | } | |
343 | } while (address != firstbuf); | |
344 | ||
345 | out: | |
346 | kfree(buf); | |
347 | ||
348 | return ret; | |
349 | } | |
350 | ||
240d2799 | 351 | static void ath6kl_install_static_wep_keys(struct ath6kl_vif *vif) |
bdcd8170 KV |
352 | { |
353 | u8 index; | |
354 | u8 keyusage; | |
355 | ||
792ecb33 | 356 | for (index = 0; index <= WMI_MAX_KEY_INDEX; index++) { |
6f2a73f9 | 357 | if (vif->wep_key_list[index].key_len) { |
bdcd8170 | 358 | keyusage = GROUP_USAGE; |
3450334f | 359 | if (index == vif->def_txkey_index) |
bdcd8170 KV |
360 | keyusage |= TX_USAGE; |
361 | ||
240d2799 | 362 | ath6kl_wmi_addkey_cmd(vif->ar->wmi, vif->fw_vif_idx, |
bdcd8170 KV |
363 | index, |
364 | WEP_CRYPT, | |
365 | keyusage, | |
6f2a73f9 | 366 | vif->wep_key_list[index].key_len, |
f4bb9a6f | 367 | NULL, 0, |
6f2a73f9 | 368 | vif->wep_key_list[index].key, |
bdcd8170 KV |
369 | KEY_OP_INIT_VAL, NULL, |
370 | NO_SYNC_WMIFLAG); | |
371 | } | |
372 | } | |
373 | } | |
374 | ||
240d2799 | 375 | void ath6kl_connect_ap_mode_bss(struct ath6kl_vif *vif, u16 channel) |
bdcd8170 | 376 | { |
240d2799 | 377 | struct ath6kl *ar = vif->ar; |
bdcd8170 | 378 | struct ath6kl_req_key *ik; |
9a5b1318 JM |
379 | int res; |
380 | u8 key_rsc[ATH6KL_KEY_SEQ_LEN]; | |
bdcd8170 | 381 | |
572e27c0 | 382 | ik = &ar->ap_mode_bkey; |
bdcd8170 | 383 | |
572e27c0 | 384 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "AP mode started on %u MHz\n", channel); |
9a5b1318 | 385 | |
3450334f | 386 | switch (vif->auth_mode) { |
572e27c0 | 387 | case NONE_AUTH: |
3450334f | 388 | if (vif->prwise_crypto == WEP_CRYPT) |
240d2799 | 389 | ath6kl_install_static_wep_keys(vif); |
4703290a JM |
390 | if (!ik->valid || ik->key_type != WAPI_CRYPT) |
391 | break; | |
392 | /* for WAPI, we need to set the delayed group key, continue: */ | |
572e27c0 JM |
393 | case WPA_PSK_AUTH: |
394 | case WPA2_PSK_AUTH: | |
395 | case (WPA_PSK_AUTH | WPA2_PSK_AUTH): | |
396 | if (!ik->valid) | |
bdcd8170 | 397 | break; |
9a5b1318 | 398 | |
cdeb8602 KV |
399 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, |
400 | "Delayed addkey for the initial group key for AP mode\n"); | |
572e27c0 JM |
401 | memset(key_rsc, 0, sizeof(key_rsc)); |
402 | res = ath6kl_wmi_addkey_cmd( | |
334234b5 | 403 | ar->wmi, vif->fw_vif_idx, ik->key_index, ik->key_type, |
f4bb9a6f JM |
404 | GROUP_USAGE, ik->key_len, key_rsc, ATH6KL_KEY_SEQ_LEN, |
405 | ik->key, | |
572e27c0 JM |
406 | KEY_OP_INIT_VAL, NULL, SYNC_BOTH_WMIFLAG); |
407 | if (res) { | |
cdeb8602 KV |
408 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, |
409 | "Delayed addkey failed: %d\n", res); | |
bdcd8170 | 410 | } |
572e27c0 | 411 | break; |
bdcd8170 KV |
412 | } |
413 | ||
b5495e66 | 414 | if (ar->last_ch != channel) |
c4f7863e | 415 | /* we actually don't know the phymode, default to HT20 */ |
b5495e66 | 416 | ath6kl_cfg80211_ch_switch_notify(vif, channel, WMI_11G_HT20); |
c4f7863e | 417 | |
240d2799 | 418 | ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx, NONE_BSS_FILTER, 0); |
59c98449 | 419 | set_bit(CONNECTED, &vif->flags); |
240d2799 | 420 | netif_carrier_on(vif->ndev); |
572e27c0 JM |
421 | } |
422 | ||
240d2799 | 423 | void ath6kl_connect_ap_mode_sta(struct ath6kl_vif *vif, u16 aid, u8 *mac_addr, |
572e27c0 | 424 | u8 keymgmt, u8 ucipher, u8 auth, |
c1762a3f | 425 | u8 assoc_req_len, u8 *assoc_info, u8 apsd_info) |
572e27c0 JM |
426 | { |
427 | u8 *ies = NULL, *wpa_ie = NULL, *pos; | |
428 | size_t ies_len = 0; | |
429 | struct station_info sinfo; | |
430 | ||
431 | ath6kl_dbg(ATH6KL_DBG_TRC, "new station %pM aid=%d\n", mac_addr, aid); | |
bdcd8170 | 432 | |
3c774bba JM |
433 | if (assoc_req_len > sizeof(struct ieee80211_hdr_3addr)) { |
434 | struct ieee80211_mgmt *mgmt = | |
435 | (struct ieee80211_mgmt *) assoc_info; | |
436 | if (ieee80211_is_assoc_req(mgmt->frame_control) && | |
437 | assoc_req_len >= sizeof(struct ieee80211_hdr_3addr) + | |
438 | sizeof(mgmt->u.assoc_req)) { | |
439 | ies = mgmt->u.assoc_req.variable; | |
440 | ies_len = assoc_info + assoc_req_len - ies; | |
441 | } else if (ieee80211_is_reassoc_req(mgmt->frame_control) && | |
442 | assoc_req_len >= sizeof(struct ieee80211_hdr_3addr) | |
443 | + sizeof(mgmt->u.reassoc_req)) { | |
444 | ies = mgmt->u.reassoc_req.variable; | |
445 | ies_len = assoc_info + assoc_req_len - ies; | |
446 | } | |
447 | } | |
448 | ||
449 | pos = ies; | |
450 | while (pos && pos + 1 < ies + ies_len) { | |
451 | if (pos + 2 + pos[1] > ies + ies_len) | |
452 | break; | |
453 | if (pos[0] == WLAN_EID_RSN) | |
454 | wpa_ie = pos; /* RSN IE */ | |
455 | else if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && | |
456 | pos[1] >= 4 && | |
457 | pos[2] == 0x00 && pos[3] == 0x50 && pos[4] == 0xf2) { | |
458 | if (pos[5] == 0x01) | |
459 | wpa_ie = pos; /* WPA IE */ | |
460 | else if (pos[5] == 0x04) { | |
461 | wpa_ie = pos; /* WPS IE */ | |
462 | break; /* overrides WPA/RSN IE */ | |
463 | } | |
30677ae0 DS |
464 | } else if (pos[0] == 0x44 && wpa_ie == NULL) { |
465 | /* | |
466 | * Note: WAPI Parameter Set IE re-uses Element ID that | |
467 | * was officially allocated for BSS AC Access Delay. As | |
468 | * such, we need to be a bit more careful on when | |
469 | * parsing the frame. However, BSS AC Access Delay | |
470 | * element is not supposed to be included in | |
471 | * (Re)Association Request frames, so this should not | |
472 | * cause problems. | |
473 | */ | |
474 | wpa_ie = pos; /* WAPI IE */ | |
475 | break; | |
3c774bba JM |
476 | } |
477 | pos += 2 + pos[1]; | |
478 | } | |
479 | ||
17741c8d | 480 | ath6kl_add_new_sta(vif, mac_addr, aid, wpa_ie, |
3c774bba | 481 | wpa_ie ? 2 + wpa_ie[1] : 0, |
c1762a3f | 482 | keymgmt, ucipher, auth, apsd_info); |
bdcd8170 KV |
483 | |
484 | /* send event to application */ | |
485 | memset(&sinfo, 0, sizeof(sinfo)); | |
486 | ||
487 | /* TODO: sinfo.generation */ | |
3c774bba JM |
488 | |
489 | sinfo.assoc_req_ies = ies; | |
490 | sinfo.assoc_req_ies_len = ies_len; | |
3c774bba | 491 | |
240d2799 | 492 | cfg80211_new_sta(vif->ndev, mac_addr, &sinfo, GFP_KERNEL); |
bdcd8170 | 493 | |
240d2799 | 494 | netif_wake_queue(vif->ndev); |
bdcd8170 KV |
495 | } |
496 | ||
bdcd8170 KV |
497 | void disconnect_timer_handler(unsigned long ptr) |
498 | { | |
499 | struct net_device *dev = (struct net_device *)ptr; | |
334234b5 | 500 | struct ath6kl_vif *vif = netdev_priv(dev); |
bdcd8170 | 501 | |
e29f25f5 | 502 | ath6kl_init_profile_info(vif); |
240d2799 | 503 | ath6kl_disconnect(vif); |
bdcd8170 KV |
504 | } |
505 | ||
240d2799 | 506 | void ath6kl_disconnect(struct ath6kl_vif *vif) |
bdcd8170 | 507 | { |
59c98449 VT |
508 | if (test_bit(CONNECTED, &vif->flags) || |
509 | test_bit(CONNECT_PEND, &vif->flags)) { | |
240d2799 | 510 | ath6kl_wmi_disconnect_cmd(vif->ar->wmi, vif->fw_vif_idx); |
bdcd8170 KV |
511 | /* |
512 | * Disconnect command is issued, clear the connect pending | |
513 | * flag. The connected flag will be cleared in | |
514 | * disconnect event notification. | |
515 | */ | |
59c98449 | 516 | clear_bit(CONNECT_PEND, &vif->flags); |
bdcd8170 KV |
517 | } |
518 | } | |
519 | ||
520 | /* WMI Event handlers */ | |
521 | ||
d92917e4 TP |
522 | void ath6kl_ready_event(void *devt, u8 *datap, u32 sw_ver, u32 abi_ver, |
523 | enum wmi_phy_cap cap) | |
bdcd8170 KV |
524 | { |
525 | struct ath6kl *ar = devt; | |
bdcd8170 | 526 | |
d66ea4f9 | 527 | memcpy(ar->mac_addr, datap, ETH_ALEN); |
b5b6f6a9 NS |
528 | |
529 | ath6kl_dbg(ATH6KL_DBG_BOOT, | |
530 | "ready event mac addr %pM sw_ver 0x%x abi_ver 0x%x cap 0x%x\n", | |
531 | ar->mac_addr, sw_ver, abi_ver, cap); | |
bdcd8170 KV |
532 | |
533 | ar->version.wlan_ver = sw_ver; | |
534 | ar->version.abi_ver = abi_ver; | |
d92917e4 | 535 | ar->hw.cap = cap; |
bdcd8170 | 536 | |
b5b6f6a9 NS |
537 | if (strlen(ar->wiphy->fw_version) == 0) { |
538 | snprintf(ar->wiphy->fw_version, | |
539 | sizeof(ar->wiphy->fw_version), | |
540 | "%u.%u.%u.%u", | |
541 | (ar->version.wlan_ver & 0xf0000000) >> 28, | |
542 | (ar->version.wlan_ver & 0x0f000000) >> 24, | |
543 | (ar->version.wlan_ver & 0x00ff0000) >> 16, | |
544 | (ar->version.wlan_ver & 0x0000ffff)); | |
545 | } | |
bdcd8170 KV |
546 | |
547 | /* indicate to the waiting thread that the ready event was received */ | |
548 | set_bit(WMI_READY, &ar->flag); | |
549 | wake_up(&ar->event_wq); | |
bdcd8170 KV |
550 | } |
551 | ||
240d2799 | 552 | void ath6kl_scan_complete_evt(struct ath6kl_vif *vif, int status) |
bdcd8170 | 553 | { |
240d2799 | 554 | struct ath6kl *ar = vif->ar; |
1c17d313 | 555 | bool aborted = false; |
59c98449 | 556 | |
1c17d313 KV |
557 | if (status != WMI_SCAN_STATUS_SUCCESS) |
558 | aborted = true; | |
559 | ||
560 | ath6kl_cfg80211_scan_complete_event(vif, aborted); | |
bdcd8170 | 561 | |
551185ca | 562 | if (!ar->usr_bss_filter) { |
59c98449 | 563 | clear_bit(CLEAR_BSSFILTER_ON_BEACON, &vif->flags); |
240d2799 VT |
564 | ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx, |
565 | NONE_BSS_FILTER, 0); | |
551185ca | 566 | } |
bdcd8170 | 567 | |
d23ace77 | 568 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "scan complete: %d\n", status); |
bdcd8170 KV |
569 | } |
570 | ||
c4f7863e TP |
571 | static int ath6kl_commit_ch_switch(struct ath6kl_vif *vif, u16 channel) |
572 | { | |
c4f7863e TP |
573 | struct ath6kl *ar = vif->ar; |
574 | ||
c4f7863e TP |
575 | vif->profile.ch = cpu_to_le16(channel); |
576 | ||
577 | switch (vif->nw_type) { | |
578 | case AP_NETWORK: | |
f21243a8 TP |
579 | /* |
580 | * reconfigure any saved RSN IE capabilites in the beacon / | |
581 | * probe response to stay in sync with the supplicant. | |
582 | */ | |
583 | if (vif->rsn_capab && | |
584 | test_bit(ATH6KL_FW_CAPABILITY_RSN_CAP_OVERRIDE, | |
585 | ar->fw_capabilities)) | |
586 | ath6kl_wmi_set_ie_cmd(ar->wmi, vif->fw_vif_idx, | |
587 | WLAN_EID_RSN, WMI_RSN_IE_CAPB, | |
588 | (const u8 *) &vif->rsn_capab, | |
589 | sizeof(vif->rsn_capab)); | |
590 | ||
c4f7863e TP |
591 | return ath6kl_wmi_ap_profile_commit(ar->wmi, vif->fw_vif_idx, |
592 | &vif->profile); | |
593 | default: | |
594 | ath6kl_err("won't switch channels nw_type=%d\n", vif->nw_type); | |
595 | return -ENOTSUPP; | |
596 | } | |
597 | } | |
598 | ||
599 | static void ath6kl_check_ch_switch(struct ath6kl *ar, u16 channel) | |
600 | { | |
c4f7863e TP |
601 | struct ath6kl_vif *vif; |
602 | int res = 0; | |
603 | ||
604 | if (!ar->want_ch_switch) | |
605 | return; | |
606 | ||
607 | spin_lock_bh(&ar->list_lock); | |
608 | list_for_each_entry(vif, &ar->vif_list, list) { | |
609 | if (ar->want_ch_switch & (1 << vif->fw_vif_idx)) | |
610 | res = ath6kl_commit_ch_switch(vif, channel); | |
611 | ||
b5495e66 TP |
612 | /* if channel switch failed, oh well we tried */ |
613 | ar->want_ch_switch &= ~(1 << vif->fw_vif_idx); | |
614 | ||
c4f7863e TP |
615 | if (res) |
616 | ath6kl_err("channel switch failed nw_type %d res %d\n", | |
617 | vif->nw_type, res); | |
618 | } | |
619 | spin_unlock_bh(&ar->list_lock); | |
620 | } | |
621 | ||
240d2799 | 622 | void ath6kl_connect_event(struct ath6kl_vif *vif, u16 channel, u8 *bssid, |
bdcd8170 KV |
623 | u16 listen_int, u16 beacon_int, |
624 | enum network_type net_type, u8 beacon_ie_len, | |
625 | u8 assoc_req_len, u8 assoc_resp_len, | |
626 | u8 *assoc_info) | |
627 | { | |
240d2799 | 628 | struct ath6kl *ar = vif->ar; |
59c98449 | 629 | |
240d2799 | 630 | ath6kl_cfg80211_connect_event(vif, channel, bssid, |
bdcd8170 KV |
631 | listen_int, beacon_int, |
632 | net_type, beacon_ie_len, | |
633 | assoc_req_len, assoc_resp_len, | |
634 | assoc_info); | |
635 | ||
8c8b65e3 | 636 | memcpy(vif->bssid, bssid, sizeof(vif->bssid)); |
f74bac54 | 637 | vif->bss_ch = channel; |
bdcd8170 | 638 | |
c4f7863e | 639 | if ((vif->nw_type == INFRA_NETWORK)) { |
334234b5 | 640 | ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx, |
8f46fccd | 641 | vif->listen_intvl_t, 0); |
c4f7863e TP |
642 | ath6kl_check_ch_switch(ar, channel); |
643 | } | |
bdcd8170 | 644 | |
240d2799 | 645 | netif_wake_queue(vif->ndev); |
bdcd8170 KV |
646 | |
647 | /* Update connect & link status atomically */ | |
478ac027 | 648 | spin_lock_bh(&vif->if_lock); |
59c98449 VT |
649 | set_bit(CONNECTED, &vif->flags); |
650 | clear_bit(CONNECT_PEND, &vif->flags); | |
240d2799 | 651 | netif_carrier_on(vif->ndev); |
478ac027 | 652 | spin_unlock_bh(&vif->if_lock); |
bdcd8170 | 653 | |
1d2a4456 | 654 | aggr_reset_state(vif->aggr_cntxt->aggr_conn); |
cf5333d7 | 655 | vif->reconnect_flag = 0; |
bdcd8170 | 656 | |
f5938f24 | 657 | if ((vif->nw_type == ADHOC_NETWORK) && ar->ibss_ps_enable) { |
bdcd8170 KV |
658 | memset(ar->node_map, 0, sizeof(ar->node_map)); |
659 | ar->node_num = 0; | |
660 | ar->next_ep_id = ENDPOINT_2; | |
661 | } | |
662 | ||
551185ca | 663 | if (!ar->usr_bss_filter) { |
59c98449 | 664 | set_bit(CLEAR_BSSFILTER_ON_BEACON, &vif->flags); |
240d2799 VT |
665 | ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx, |
666 | CURRENT_BSS_FILTER, 0); | |
551185ca | 667 | } |
bdcd8170 KV |
668 | } |
669 | ||
240d2799 | 670 | void ath6kl_tkip_micerr_event(struct ath6kl_vif *vif, u8 keyid, bool ismcast) |
bdcd8170 KV |
671 | { |
672 | struct ath6kl_sta *sta; | |
240d2799 | 673 | struct ath6kl *ar = vif->ar; |
bdcd8170 | 674 | u8 tsc[6]; |
240d2799 | 675 | |
bdcd8170 KV |
676 | /* |
677 | * For AP case, keyid will have aid of STA which sent pkt with | |
678 | * MIC error. Use this aid to get MAC & send it to hostapd. | |
679 | */ | |
f5938f24 | 680 | if (vif->nw_type == AP_NETWORK) { |
bdcd8170 KV |
681 | sta = ath6kl_find_sta_by_aid(ar, (keyid >> 2)); |
682 | if (!sta) | |
683 | return; | |
684 | ||
685 | ath6kl_dbg(ATH6KL_DBG_TRC, | |
686 | "ap tkip mic error received from aid=%d\n", keyid); | |
687 | ||
688 | memset(tsc, 0, sizeof(tsc)); /* FIX: get correct TSC */ | |
240d2799 | 689 | cfg80211_michael_mic_failure(vif->ndev, sta->mac, |
bdcd8170 KV |
690 | NL80211_KEYTYPE_PAIRWISE, keyid, |
691 | tsc, GFP_KERNEL); | |
a5d8f9df | 692 | } else { |
240d2799 | 693 | ath6kl_cfg80211_tkip_micerr_event(vif, keyid, ismcast); |
a5d8f9df | 694 | } |
bdcd8170 KV |
695 | } |
696 | ||
240d2799 | 697 | static void ath6kl_update_target_stats(struct ath6kl_vif *vif, u8 *ptr, u32 len) |
bdcd8170 KV |
698 | { |
699 | struct wmi_target_stats *tgt_stats = | |
700 | (struct wmi_target_stats *) ptr; | |
240d2799 | 701 | struct ath6kl *ar = vif->ar; |
b95907a7 | 702 | struct target_stats *stats = &vif->target_stats; |
bdcd8170 | 703 | struct tkip_ccmp_stats *ccmp_stats; |
c1d32d30 | 704 | s32 rate; |
bdcd8170 KV |
705 | u8 ac; |
706 | ||
707 | if (len < sizeof(*tgt_stats)) | |
708 | return; | |
709 | ||
bdcd8170 KV |
710 | ath6kl_dbg(ATH6KL_DBG_TRC, "updating target stats\n"); |
711 | ||
712 | stats->tx_pkt += le32_to_cpu(tgt_stats->stats.tx.pkt); | |
713 | stats->tx_byte += le32_to_cpu(tgt_stats->stats.tx.byte); | |
714 | stats->tx_ucast_pkt += le32_to_cpu(tgt_stats->stats.tx.ucast_pkt); | |
715 | stats->tx_ucast_byte += le32_to_cpu(tgt_stats->stats.tx.ucast_byte); | |
716 | stats->tx_mcast_pkt += le32_to_cpu(tgt_stats->stats.tx.mcast_pkt); | |
717 | stats->tx_mcast_byte += le32_to_cpu(tgt_stats->stats.tx.mcast_byte); | |
718 | stats->tx_bcast_pkt += le32_to_cpu(tgt_stats->stats.tx.bcast_pkt); | |
719 | stats->tx_bcast_byte += le32_to_cpu(tgt_stats->stats.tx.bcast_byte); | |
720 | stats->tx_rts_success_cnt += | |
721 | le32_to_cpu(tgt_stats->stats.tx.rts_success_cnt); | |
722 | ||
723 | for (ac = 0; ac < WMM_NUM_AC; ac++) | |
724 | stats->tx_pkt_per_ac[ac] += | |
725 | le32_to_cpu(tgt_stats->stats.tx.pkt_per_ac[ac]); | |
726 | ||
727 | stats->tx_err += le32_to_cpu(tgt_stats->stats.tx.err); | |
728 | stats->tx_fail_cnt += le32_to_cpu(tgt_stats->stats.tx.fail_cnt); | |
729 | stats->tx_retry_cnt += le32_to_cpu(tgt_stats->stats.tx.retry_cnt); | |
730 | stats->tx_mult_retry_cnt += | |
731 | le32_to_cpu(tgt_stats->stats.tx.mult_retry_cnt); | |
732 | stats->tx_rts_fail_cnt += | |
733 | le32_to_cpu(tgt_stats->stats.tx.rts_fail_cnt); | |
c1d32d30 JW |
734 | |
735 | rate = a_sle32_to_cpu(tgt_stats->stats.tx.ucast_rate); | |
736 | stats->tx_ucast_rate = ath6kl_wmi_get_rate(ar->wmi, rate); | |
bdcd8170 KV |
737 | |
738 | stats->rx_pkt += le32_to_cpu(tgt_stats->stats.rx.pkt); | |
739 | stats->rx_byte += le32_to_cpu(tgt_stats->stats.rx.byte); | |
740 | stats->rx_ucast_pkt += le32_to_cpu(tgt_stats->stats.rx.ucast_pkt); | |
741 | stats->rx_ucast_byte += le32_to_cpu(tgt_stats->stats.rx.ucast_byte); | |
742 | stats->rx_mcast_pkt += le32_to_cpu(tgt_stats->stats.rx.mcast_pkt); | |
743 | stats->rx_mcast_byte += le32_to_cpu(tgt_stats->stats.rx.mcast_byte); | |
744 | stats->rx_bcast_pkt += le32_to_cpu(tgt_stats->stats.rx.bcast_pkt); | |
745 | stats->rx_bcast_byte += le32_to_cpu(tgt_stats->stats.rx.bcast_byte); | |
746 | stats->rx_frgment_pkt += le32_to_cpu(tgt_stats->stats.rx.frgment_pkt); | |
747 | stats->rx_err += le32_to_cpu(tgt_stats->stats.rx.err); | |
748 | stats->rx_crc_err += le32_to_cpu(tgt_stats->stats.rx.crc_err); | |
749 | stats->rx_key_cache_miss += | |
750 | le32_to_cpu(tgt_stats->stats.rx.key_cache_miss); | |
751 | stats->rx_decrypt_err += le32_to_cpu(tgt_stats->stats.rx.decrypt_err); | |
752 | stats->rx_dupl_frame += le32_to_cpu(tgt_stats->stats.rx.dupl_frame); | |
c1d32d30 JW |
753 | |
754 | rate = a_sle32_to_cpu(tgt_stats->stats.rx.ucast_rate); | |
755 | stats->rx_ucast_rate = ath6kl_wmi_get_rate(ar->wmi, rate); | |
bdcd8170 KV |
756 | |
757 | ccmp_stats = &tgt_stats->stats.tkip_ccmp_stats; | |
758 | ||
759 | stats->tkip_local_mic_fail += | |
760 | le32_to_cpu(ccmp_stats->tkip_local_mic_fail); | |
761 | stats->tkip_cnter_measures_invoked += | |
762 | le32_to_cpu(ccmp_stats->tkip_cnter_measures_invoked); | |
763 | stats->tkip_fmt_err += le32_to_cpu(ccmp_stats->tkip_fmt_err); | |
764 | ||
765 | stats->ccmp_fmt_err += le32_to_cpu(ccmp_stats->ccmp_fmt_err); | |
766 | stats->ccmp_replays += le32_to_cpu(ccmp_stats->ccmp_replays); | |
767 | ||
768 | stats->pwr_save_fail_cnt += | |
769 | le32_to_cpu(tgt_stats->pm_stats.pwr_save_failure_cnt); | |
770 | stats->noise_floor_calib = | |
771 | a_sle32_to_cpu(tgt_stats->noise_floor_calib); | |
772 | ||
773 | stats->cs_bmiss_cnt += | |
774 | le32_to_cpu(tgt_stats->cserv_stats.cs_bmiss_cnt); | |
775 | stats->cs_low_rssi_cnt += | |
776 | le32_to_cpu(tgt_stats->cserv_stats.cs_low_rssi_cnt); | |
777 | stats->cs_connect_cnt += | |
778 | le16_to_cpu(tgt_stats->cserv_stats.cs_connect_cnt); | |
779 | stats->cs_discon_cnt += | |
780 | le16_to_cpu(tgt_stats->cserv_stats.cs_discon_cnt); | |
781 | ||
782 | stats->cs_ave_beacon_rssi = | |
783 | a_sle16_to_cpu(tgt_stats->cserv_stats.cs_ave_beacon_rssi); | |
784 | ||
785 | stats->cs_last_roam_msec = | |
786 | tgt_stats->cserv_stats.cs_last_roam_msec; | |
787 | stats->cs_snr = tgt_stats->cserv_stats.cs_snr; | |
788 | stats->cs_rssi = a_sle16_to_cpu(tgt_stats->cserv_stats.cs_rssi); | |
789 | ||
790 | stats->lq_val = le32_to_cpu(tgt_stats->lq_val); | |
791 | ||
792 | stats->wow_pkt_dropped += | |
793 | le32_to_cpu(tgt_stats->wow_stats.wow_pkt_dropped); | |
794 | stats->wow_host_pkt_wakeups += | |
795 | tgt_stats->wow_stats.wow_host_pkt_wakeups; | |
796 | stats->wow_host_evt_wakeups += | |
797 | tgt_stats->wow_stats.wow_host_evt_wakeups; | |
798 | stats->wow_evt_discarded += | |
799 | le16_to_cpu(tgt_stats->wow_stats.wow_evt_discarded); | |
800 | ||
f0446ea9 RM |
801 | stats->arp_received = le32_to_cpu(tgt_stats->arp_stats.arp_received); |
802 | stats->arp_replied = le32_to_cpu(tgt_stats->arp_stats.arp_replied); | |
803 | stats->arp_matched = le32_to_cpu(tgt_stats->arp_stats.arp_matched); | |
804 | ||
b95907a7 VT |
805 | if (test_bit(STATS_UPDATE_PEND, &vif->flags)) { |
806 | clear_bit(STATS_UPDATE_PEND, &vif->flags); | |
bdcd8170 KV |
807 | wake_up(&ar->event_wq); |
808 | } | |
809 | } | |
810 | ||
811 | static void ath6kl_add_le32(__le32 *var, __le32 val) | |
812 | { | |
813 | *var = cpu_to_le32(le32_to_cpu(*var) + le32_to_cpu(val)); | |
814 | } | |
815 | ||
240d2799 | 816 | void ath6kl_tgt_stats_event(struct ath6kl_vif *vif, u8 *ptr, u32 len) |
bdcd8170 KV |
817 | { |
818 | struct wmi_ap_mode_stat *p = (struct wmi_ap_mode_stat *) ptr; | |
240d2799 | 819 | struct ath6kl *ar = vif->ar; |
bdcd8170 KV |
820 | struct wmi_ap_mode_stat *ap = &ar->ap_stats; |
821 | struct wmi_per_sta_stat *st_ap, *st_p; | |
822 | u8 ac; | |
823 | ||
f5938f24 | 824 | if (vif->nw_type == AP_NETWORK) { |
bdcd8170 KV |
825 | if (len < sizeof(*p)) |
826 | return; | |
827 | ||
828 | for (ac = 0; ac < AP_MAX_NUM_STA; ac++) { | |
829 | st_ap = &ap->sta[ac]; | |
830 | st_p = &p->sta[ac]; | |
831 | ||
832 | ath6kl_add_le32(&st_ap->tx_bytes, st_p->tx_bytes); | |
833 | ath6kl_add_le32(&st_ap->tx_pkts, st_p->tx_pkts); | |
834 | ath6kl_add_le32(&st_ap->tx_error, st_p->tx_error); | |
835 | ath6kl_add_le32(&st_ap->tx_discard, st_p->tx_discard); | |
836 | ath6kl_add_le32(&st_ap->rx_bytes, st_p->rx_bytes); | |
837 | ath6kl_add_le32(&st_ap->rx_pkts, st_p->rx_pkts); | |
838 | ath6kl_add_le32(&st_ap->rx_error, st_p->rx_error); | |
839 | ath6kl_add_le32(&st_ap->rx_discard, st_p->rx_discard); | |
840 | } | |
841 | ||
842 | } else { | |
240d2799 | 843 | ath6kl_update_target_stats(vif, ptr, len); |
bdcd8170 KV |
844 | } |
845 | } | |
846 | ||
847 | void ath6kl_wakeup_event(void *dev) | |
848 | { | |
849 | struct ath6kl *ar = (struct ath6kl *) dev; | |
850 | ||
851 | wake_up(&ar->event_wq); | |
852 | } | |
853 | ||
854 | void ath6kl_txpwr_rx_evt(void *devt, u8 tx_pwr) | |
855 | { | |
856 | struct ath6kl *ar = (struct ath6kl *) devt; | |
857 | ||
858 | ar->tx_pwr = tx_pwr; | |
859 | wake_up(&ar->event_wq); | |
860 | } | |
861 | ||
240d2799 | 862 | void ath6kl_pspoll_event(struct ath6kl_vif *vif, u8 aid) |
bdcd8170 KV |
863 | { |
864 | struct ath6kl_sta *conn; | |
865 | struct sk_buff *skb; | |
866 | bool psq_empty = false; | |
240d2799 | 867 | struct ath6kl *ar = vif->ar; |
d0ff7383 | 868 | struct ath6kl_mgmt_buff *mgmt_buf; |
bdcd8170 KV |
869 | |
870 | conn = ath6kl_find_sta_by_aid(ar, aid); | |
871 | ||
872 | if (!conn) | |
873 | return; | |
874 | /* | |
875 | * Send out a packet queued on ps queue. When the ps queue | |
876 | * becomes empty update the PVB for this station. | |
877 | */ | |
878 | spin_lock_bh(&conn->psq_lock); | |
d0ff7383 | 879 | psq_empty = skb_queue_empty(&conn->psq) && (conn->mgmt_psq_len == 0); |
bdcd8170 KV |
880 | spin_unlock_bh(&conn->psq_lock); |
881 | ||
882 | if (psq_empty) | |
883 | /* TODO: Send out a NULL data frame */ | |
884 | return; | |
885 | ||
886 | spin_lock_bh(&conn->psq_lock); | |
d0ff7383 NG |
887 | if (conn->mgmt_psq_len > 0) { |
888 | mgmt_buf = list_first_entry(&conn->mgmt_psq, | |
889 | struct ath6kl_mgmt_buff, list); | |
890 | list_del(&mgmt_buf->list); | |
891 | conn->mgmt_psq_len--; | |
892 | spin_unlock_bh(&conn->psq_lock); | |
893 | ||
894 | conn->sta_flags |= STA_PS_POLLED; | |
895 | ath6kl_wmi_send_mgmt_cmd(ar->wmi, vif->fw_vif_idx, | |
896 | mgmt_buf->id, mgmt_buf->freq, | |
897 | mgmt_buf->wait, mgmt_buf->buf, | |
898 | mgmt_buf->len, mgmt_buf->no_cck); | |
899 | conn->sta_flags &= ~STA_PS_POLLED; | |
900 | kfree(mgmt_buf); | |
901 | } else { | |
902 | skb = skb_dequeue(&conn->psq); | |
903 | spin_unlock_bh(&conn->psq_lock); | |
bdcd8170 | 904 | |
d0ff7383 NG |
905 | conn->sta_flags |= STA_PS_POLLED; |
906 | ath6kl_data_tx(skb, vif->ndev); | |
907 | conn->sta_flags &= ~STA_PS_POLLED; | |
908 | } | |
bdcd8170 KV |
909 | |
910 | spin_lock_bh(&conn->psq_lock); | |
d0ff7383 | 911 | psq_empty = skb_queue_empty(&conn->psq) && (conn->mgmt_psq_len == 0); |
bdcd8170 KV |
912 | spin_unlock_bh(&conn->psq_lock); |
913 | ||
914 | if (psq_empty) | |
334234b5 | 915 | ath6kl_wmi_set_pvb_cmd(ar->wmi, vif->fw_vif_idx, conn->aid, 0); |
bdcd8170 KV |
916 | } |
917 | ||
240d2799 | 918 | void ath6kl_dtimexpiry_event(struct ath6kl_vif *vif) |
bdcd8170 KV |
919 | { |
920 | bool mcastq_empty = false; | |
921 | struct sk_buff *skb; | |
240d2799 | 922 | struct ath6kl *ar = vif->ar; |
bdcd8170 KV |
923 | |
924 | /* | |
925 | * If there are no associated STAs, ignore the DTIM expiry event. | |
926 | * There can be potential race conditions where the last associated | |
927 | * STA may disconnect & before the host could clear the 'Indicate | |
928 | * DTIM' request to the firmware, the firmware would have just | |
929 | * indicated a DTIM expiry event. The race is between 'clear DTIM | |
930 | * expiry cmd' going from the host to the firmware & the DTIM | |
931 | * expiry event happening from the firmware to the host. | |
932 | */ | |
933 | if (!ar->sta_list_index) | |
934 | return; | |
935 | ||
936 | spin_lock_bh(&ar->mcastpsq_lock); | |
937 | mcastq_empty = skb_queue_empty(&ar->mcastpsq); | |
938 | spin_unlock_bh(&ar->mcastpsq_lock); | |
939 | ||
940 | if (mcastq_empty) | |
941 | return; | |
942 | ||
943 | /* set the STA flag to dtim_expired for the frame to go out */ | |
59c98449 | 944 | set_bit(DTIM_EXPIRED, &vif->flags); |
bdcd8170 KV |
945 | |
946 | spin_lock_bh(&ar->mcastpsq_lock); | |
947 | while ((skb = skb_dequeue(&ar->mcastpsq)) != NULL) { | |
948 | spin_unlock_bh(&ar->mcastpsq_lock); | |
949 | ||
240d2799 | 950 | ath6kl_data_tx(skb, vif->ndev); |
bdcd8170 KV |
951 | |
952 | spin_lock_bh(&ar->mcastpsq_lock); | |
953 | } | |
954 | spin_unlock_bh(&ar->mcastpsq_lock); | |
955 | ||
59c98449 | 956 | clear_bit(DTIM_EXPIRED, &vif->flags); |
bdcd8170 KV |
957 | |
958 | /* clear the LSB of the BitMapCtl field of the TIM IE */ | |
334234b5 | 959 | ath6kl_wmi_set_pvb_cmd(ar->wmi, vif->fw_vif_idx, MCAST_AID, 0); |
bdcd8170 KV |
960 | } |
961 | ||
240d2799 | 962 | void ath6kl_disconnect_event(struct ath6kl_vif *vif, u8 reason, u8 *bssid, |
bdcd8170 KV |
963 | u8 assoc_resp_len, u8 *assoc_info, |
964 | u16 prot_reason_status) | |
965 | { | |
240d2799 | 966 | struct ath6kl *ar = vif->ar; |
59c98449 | 967 | |
f5938f24 | 968 | if (vif->nw_type == AP_NETWORK) { |
c4f7863e TP |
969 | /* disconnect due to other STA vif switching channels */ |
970 | if (reason == BSS_DISCONNECTED && | |
b5495e66 | 971 | prot_reason_status == WMI_AP_REASON_STA_ROAM) { |
c4f7863e | 972 | ar->want_ch_switch |= 1 << vif->fw_vif_idx; |
b5495e66 TP |
973 | /* bail back to this channel if STA vif fails connect */ |
974 | ar->last_ch = le16_to_cpu(vif->profile.ch); | |
975 | } | |
c4f7863e | 976 | |
07033ce2 PP |
977 | if (prot_reason_status == WMI_AP_REASON_MAX_STA) { |
978 | /* send max client reached notification to user space */ | |
979 | cfg80211_conn_failed(vif->ndev, bssid, | |
980 | NL80211_CONN_FAIL_MAX_CLIENTS, | |
981 | GFP_KERNEL); | |
982 | } | |
983 | ||
698bf867 PP |
984 | if (prot_reason_status == WMI_AP_REASON_ACL) { |
985 | /* send blocked client notification to user space */ | |
986 | cfg80211_conn_failed(vif->ndev, bssid, | |
987 | NL80211_CONN_FAIL_BLOCKED_CLIENT, | |
988 | GFP_KERNEL); | |
989 | } | |
990 | ||
bdcd8170 KV |
991 | if (!ath6kl_remove_sta(ar, bssid, prot_reason_status)) |
992 | return; | |
993 | ||
994 | /* if no more associated STAs, empty the mcast PS q */ | |
995 | if (ar->sta_list_index == 0) { | |
996 | spin_lock_bh(&ar->mcastpsq_lock); | |
997 | skb_queue_purge(&ar->mcastpsq); | |
998 | spin_unlock_bh(&ar->mcastpsq_lock); | |
999 | ||
1000 | /* clear the LSB of the TIM IE's BitMapCtl field */ | |
1001 | if (test_bit(WMI_READY, &ar->flag)) | |
334234b5 VT |
1002 | ath6kl_wmi_set_pvb_cmd(ar->wmi, vif->fw_vif_idx, |
1003 | MCAST_AID, 0); | |
bdcd8170 KV |
1004 | } |
1005 | ||
1006 | if (!is_broadcast_ether_addr(bssid)) { | |
1007 | /* send event to application */ | |
240d2799 | 1008 | cfg80211_del_sta(vif->ndev, bssid, GFP_KERNEL); |
bdcd8170 KV |
1009 | } |
1010 | ||
240d2799 | 1011 | if (memcmp(vif->ndev->dev_addr, bssid, ETH_ALEN) == 0) { |
6f2a73f9 | 1012 | memset(vif->wep_key_list, 0, sizeof(vif->wep_key_list)); |
59c98449 | 1013 | clear_bit(CONNECTED, &vif->flags); |
151411e8 | 1014 | } |
bdcd8170 KV |
1015 | return; |
1016 | } | |
1017 | ||
240d2799 | 1018 | ath6kl_cfg80211_disconnect_event(vif, reason, bssid, |
96f1fadc KV |
1019 | assoc_resp_len, assoc_info, |
1020 | prot_reason_status); | |
bdcd8170 | 1021 | |
1d2a4456 | 1022 | aggr_reset_state(vif->aggr_cntxt->aggr_conn); |
bdcd8170 | 1023 | |
de3ad713 | 1024 | del_timer(&vif->disconnect_timer); |
bdcd8170 | 1025 | |
d23ace77 | 1026 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "disconnect reason is %d\n", reason); |
bdcd8170 KV |
1027 | |
1028 | /* | |
1029 | * If the event is due to disconnect cmd from the host, only they | |
1030 | * the target would stop trying to connect. Under any other | |
1031 | * condition, target would keep trying to connect. | |
1032 | */ | |
1033 | if (reason == DISCONNECT_CMD) { | |
1034 | if (!ar->usr_bss_filter && test_bit(WMI_READY, &ar->flag)) | |
240d2799 VT |
1035 | ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx, |
1036 | NONE_BSS_FILTER, 0); | |
bdcd8170 | 1037 | } else { |
59c98449 | 1038 | set_bit(CONNECT_PEND, &vif->flags); |
bdcd8170 | 1039 | if (((reason == ASSOC_FAILED) && |
96f1fadc | 1040 | (prot_reason_status == 0x11)) || |
ddc3d77c KV |
1041 | ((reason == ASSOC_FAILED) && (prot_reason_status == 0x0) && |
1042 | (vif->reconnect_flag == 1))) { | |
59c98449 | 1043 | set_bit(CONNECTED, &vif->flags); |
bdcd8170 KV |
1044 | return; |
1045 | } | |
1046 | } | |
1047 | ||
b5495e66 TP |
1048 | /* restart disconnected concurrent vifs waiting for new channel */ |
1049 | ath6kl_check_ch_switch(ar, ar->last_ch); | |
1050 | ||
bdcd8170 | 1051 | /* update connect & link status atomically */ |
478ac027 | 1052 | spin_lock_bh(&vif->if_lock); |
59c98449 | 1053 | clear_bit(CONNECTED, &vif->flags); |
240d2799 | 1054 | netif_carrier_off(vif->ndev); |
478ac027 | 1055 | spin_unlock_bh(&vif->if_lock); |
bdcd8170 | 1056 | |
cf5333d7 VT |
1057 | if ((reason != CSERV_DISCONNECT) || (vif->reconnect_flag != 1)) |
1058 | vif->reconnect_flag = 0; | |
bdcd8170 KV |
1059 | |
1060 | if (reason != CSERV_DISCONNECT) | |
1061 | ar->user_key_ctrl = 0; | |
1062 | ||
240d2799 | 1063 | netif_stop_queue(vif->ndev); |
8c8b65e3 | 1064 | memset(vif->bssid, 0, sizeof(vif->bssid)); |
f74bac54 | 1065 | vif->bss_ch = 0; |
bdcd8170 KV |
1066 | |
1067 | ath6kl_tx_data_cleanup(ar); | |
1068 | } | |
1069 | ||
990bd915 VT |
1070 | struct ath6kl_vif *ath6kl_vif_first(struct ath6kl *ar) |
1071 | { | |
1072 | struct ath6kl_vif *vif; | |
1073 | ||
11f6e40d | 1074 | spin_lock_bh(&ar->list_lock); |
990bd915 | 1075 | if (list_empty(&ar->vif_list)) { |
11f6e40d | 1076 | spin_unlock_bh(&ar->list_lock); |
990bd915 VT |
1077 | return NULL; |
1078 | } | |
1079 | ||
1080 | vif = list_first_entry(&ar->vif_list, struct ath6kl_vif, list); | |
1081 | ||
11f6e40d | 1082 | spin_unlock_bh(&ar->list_lock); |
990bd915 VT |
1083 | |
1084 | return vif; | |
1085 | } | |
1086 | ||
bdcd8170 KV |
1087 | static int ath6kl_open(struct net_device *dev) |
1088 | { | |
59c98449 | 1089 | struct ath6kl_vif *vif = netdev_priv(dev); |
bdcd8170 | 1090 | |
59c98449 | 1091 | set_bit(WLAN_ENABLED, &vif->flags); |
bdcd8170 | 1092 | |
59c98449 | 1093 | if (test_bit(CONNECTED, &vif->flags)) { |
bdcd8170 KV |
1094 | netif_carrier_on(dev); |
1095 | netif_wake_queue(dev); | |
a5d8f9df | 1096 | } else { |
bdcd8170 | 1097 | netif_carrier_off(dev); |
a5d8f9df | 1098 | } |
bdcd8170 | 1099 | |
bdcd8170 KV |
1100 | return 0; |
1101 | } | |
1102 | ||
1103 | static int ath6kl_close(struct net_device *dev) | |
1104 | { | |
59c98449 | 1105 | struct ath6kl_vif *vif = netdev_priv(dev); |
bdcd8170 KV |
1106 | |
1107 | netif_stop_queue(dev); | |
1108 | ||
7125f01d | 1109 | ath6kl_cfg80211_stop(vif); |
bdcd8170 | 1110 | |
68469341 KV |
1111 | clear_bit(WLAN_ENABLED, &vif->flags); |
1112 | ||
bdcd8170 KV |
1113 | return 0; |
1114 | } | |
1115 | ||
d6f80261 KV |
1116 | static int ath6kl_set_features(struct net_device *dev, |
1117 | netdev_features_t features) | |
bc48ad31 RP |
1118 | { |
1119 | struct ath6kl_vif *vif = netdev_priv(dev); | |
1120 | struct ath6kl *ar = vif->ar; | |
1121 | int err = 0; | |
1122 | ||
1123 | if ((features & NETIF_F_RXCSUM) && | |
1124 | (ar->rx_meta_ver != WMI_META_VERSION_2)) { | |
1125 | ar->rx_meta_ver = WMI_META_VERSION_2; | |
1126 | err = ath6kl_wmi_set_rx_frame_format_cmd(ar->wmi, | |
1127 | vif->fw_vif_idx, | |
1128 | ar->rx_meta_ver, 0, 0); | |
1129 | if (err) { | |
1130 | dev->features = features & ~NETIF_F_RXCSUM; | |
1131 | return err; | |
1132 | } | |
1133 | } else if (!(features & NETIF_F_RXCSUM) && | |
1134 | (ar->rx_meta_ver == WMI_META_VERSION_2)) { | |
1135 | ar->rx_meta_ver = 0; | |
1136 | err = ath6kl_wmi_set_rx_frame_format_cmd(ar->wmi, | |
1137 | vif->fw_vif_idx, | |
1138 | ar->rx_meta_ver, 0, 0); | |
1139 | if (err) { | |
1140 | dev->features = features | NETIF_F_RXCSUM; | |
1141 | return err; | |
1142 | } | |
bc48ad31 RP |
1143 | } |
1144 | ||
1145 | return err; | |
1146 | } | |
1147 | ||
80abaf9b VT |
1148 | static void ath6kl_set_multicast_list(struct net_device *ndev) |
1149 | { | |
1150 | struct ath6kl_vif *vif = netdev_priv(ndev); | |
6251d801 | 1151 | bool mc_all_on = false; |
80abaf9b VT |
1152 | int mc_count = netdev_mc_count(ndev); |
1153 | struct netdev_hw_addr *ha; | |
1154 | bool found; | |
1155 | struct ath6kl_mc_filter *mc_filter, *tmp; | |
1156 | struct list_head mc_filter_new; | |
1157 | int ret; | |
1158 | ||
1159 | if (!test_bit(WMI_READY, &vif->ar->flag) || | |
1160 | !test_bit(WLAN_ENABLED, &vif->flags)) | |
1161 | return; | |
1162 | ||
6251d801 | 1163 | /* Enable multicast-all filter. */ |
80abaf9b VT |
1164 | mc_all_on = !!(ndev->flags & IFF_PROMISC) || |
1165 | !!(ndev->flags & IFF_ALLMULTI) || | |
1166 | !!(mc_count > ATH6K_MAX_MC_FILTERS_PER_LIST); | |
1167 | ||
6251d801 NG |
1168 | if (mc_all_on) |
1169 | set_bit(NETDEV_MCAST_ALL_ON, &vif->flags); | |
1170 | else | |
1171 | clear_bit(NETDEV_MCAST_ALL_ON, &vif->flags); | |
80abaf9b | 1172 | |
6821d4f0 NG |
1173 | if (test_bit(ATH6KL_FW_CAPABILITY_WOW_MULTICAST_FILTER, |
1174 | vif->ar->fw_capabilities)) { | |
1175 | mc_all_on = mc_all_on || (vif->ar->state == ATH6KL_STATE_ON); | |
1176 | } | |
6251d801 NG |
1177 | |
1178 | if (!(ndev->flags & IFF_MULTICAST)) { | |
1179 | mc_all_on = false; | |
1180 | set_bit(NETDEV_MCAST_ALL_OFF, &vif->flags); | |
1181 | } else { | |
1182 | clear_bit(NETDEV_MCAST_ALL_OFF, &vif->flags); | |
1183 | } | |
1184 | ||
1185 | /* Enable/disable "multicast-all" filter*/ | |
1186 | ath6kl_dbg(ATH6KL_DBG_TRC, "%s multicast-all filter\n", | |
1187 | mc_all_on ? "enabling" : "disabling"); | |
1188 | ||
1189 | ret = ath6kl_wmi_mcast_filter_cmd(vif->ar->wmi, vif->fw_vif_idx, | |
80abaf9b | 1190 | mc_all_on); |
6251d801 NG |
1191 | if (ret) { |
1192 | ath6kl_warn("Failed to %s multicast-all receive\n", | |
1193 | mc_all_on ? "enable" : "disable"); | |
80abaf9b VT |
1194 | return; |
1195 | } | |
1196 | ||
6251d801 NG |
1197 | if (test_bit(NETDEV_MCAST_ALL_ON, &vif->flags)) |
1198 | return; | |
1199 | ||
1200 | /* Keep the driver and firmware mcast list in sync. */ | |
80abaf9b VT |
1201 | list_for_each_entry_safe(mc_filter, tmp, &vif->mc_filter, list) { |
1202 | found = false; | |
1203 | netdev_for_each_mc_addr(ha, ndev) { | |
1204 | if (memcmp(ha->addr, mc_filter->hw_addr, | |
96f1fadc | 1205 | ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE) == 0) { |
80abaf9b VT |
1206 | found = true; |
1207 | break; | |
1208 | } | |
1209 | } | |
1210 | ||
1211 | if (!found) { | |
1212 | /* | |
1213 | * Delete the filter which was previously set | |
1214 | * but not in the new request. | |
1215 | */ | |
1216 | ath6kl_dbg(ATH6KL_DBG_TRC, | |
1217 | "Removing %pM from multicast filter\n", | |
1218 | mc_filter->hw_addr); | |
1219 | ret = ath6kl_wmi_add_del_mcast_filter_cmd(vif->ar->wmi, | |
1220 | vif->fw_vif_idx, mc_filter->hw_addr, | |
1221 | false); | |
1222 | if (ret) { | |
1223 | ath6kl_warn("Failed to remove multicast filter:%pM\n", | |
96f1fadc | 1224 | mc_filter->hw_addr); |
80abaf9b VT |
1225 | return; |
1226 | } | |
1227 | ||
1228 | list_del(&mc_filter->list); | |
1229 | kfree(mc_filter); | |
1230 | } | |
1231 | } | |
1232 | ||
1233 | INIT_LIST_HEAD(&mc_filter_new); | |
1234 | ||
1235 | netdev_for_each_mc_addr(ha, ndev) { | |
1236 | found = false; | |
1237 | list_for_each_entry(mc_filter, &vif->mc_filter, list) { | |
1238 | if (memcmp(ha->addr, mc_filter->hw_addr, | |
96f1fadc | 1239 | ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE) == 0) { |
80abaf9b VT |
1240 | found = true; |
1241 | break; | |
1242 | } | |
1243 | } | |
1244 | ||
1245 | if (!found) { | |
1246 | mc_filter = kzalloc(sizeof(struct ath6kl_mc_filter), | |
1247 | GFP_ATOMIC); | |
1248 | if (!mc_filter) { | |
1249 | WARN_ON(1); | |
1250 | goto out; | |
1251 | } | |
1252 | ||
1253 | memcpy(mc_filter->hw_addr, ha->addr, | |
1254 | ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE); | |
1255 | /* Set the multicast filter */ | |
1256 | ath6kl_dbg(ATH6KL_DBG_TRC, | |
1257 | "Adding %pM to multicast filter list\n", | |
1258 | mc_filter->hw_addr); | |
1259 | ret = ath6kl_wmi_add_del_mcast_filter_cmd(vif->ar->wmi, | |
1260 | vif->fw_vif_idx, mc_filter->hw_addr, | |
1261 | true); | |
1262 | if (ret) { | |
1263 | ath6kl_warn("Failed to add multicast filter :%pM\n", | |
96f1fadc | 1264 | mc_filter->hw_addr); |
80abaf9b VT |
1265 | kfree(mc_filter); |
1266 | goto out; | |
1267 | } | |
1268 | ||
1269 | list_add_tail(&mc_filter->list, &mc_filter_new); | |
1270 | } | |
1271 | } | |
1272 | ||
1273 | out: | |
1274 | list_splice_tail(&mc_filter_new, &vif->mc_filter); | |
1275 | } | |
1276 | ||
4269a930 | 1277 | static const struct net_device_ops ath6kl_netdev_ops = { |
bdcd8170 KV |
1278 | .ndo_open = ath6kl_open, |
1279 | .ndo_stop = ath6kl_close, | |
1280 | .ndo_start_xmit = ath6kl_data_tx, | |
bc48ad31 | 1281 | .ndo_set_features = ath6kl_set_features, |
80abaf9b | 1282 | .ndo_set_rx_mode = ath6kl_set_multicast_list, |
bdcd8170 KV |
1283 | }; |
1284 | ||
1285 | void init_netdev(struct net_device *dev) | |
1286 | { | |
78803770 JW |
1287 | struct ath6kl *ar = ath6kl_priv(dev); |
1288 | ||
bdcd8170 | 1289 | dev->netdev_ops = &ath6kl_netdev_ops; |
cf124db5 | 1290 | dev->needs_free_netdev = true; |
bdcd8170 KV |
1291 | dev->watchdog_timeo = ATH6KL_TX_TIMEOUT; |
1292 | ||
1293 | dev->needed_headroom = ETH_HLEN; | |
6a3e4e06 MK |
1294 | dev->needed_headroom += roundup(sizeof(struct ath6kl_llc_snap_hdr) + |
1295 | sizeof(struct wmi_data_hdr) + | |
1296 | HTC_HDR_LENGTH + | |
1297 | WMI_MAX_TX_META_SZ + | |
1298 | ATH6KL_HTC_ALIGN_BYTES, 4); | |
bdcd8170 | 1299 | |
78803770 JW |
1300 | if (!test_bit(ATH6KL_FW_CAPABILITY_NO_IP_CHECKSUM, |
1301 | ar->fw_capabilities)) | |
1302 | dev->hw_features |= NETIF_F_IP_CSUM | NETIF_F_RXCSUM; | |
4705b703 | 1303 | |
bdcd8170 KV |
1304 | return; |
1305 | } |