Commit | Line | Data |
---|---|---|
a84fab3c CL |
1 | /* |
2 | * Atheros CARL9170 driver | |
3 | * | |
4 | * 802.11 & command trap routines | |
5 | * | |
6 | * Copyright 2008, Johannes Berg <johannes@sipsolutions.net> | |
7 | * Copyright 2009, 2010, Christian Lamparter <chunkeey@googlemail.com> | |
8 | * | |
9 | * This program is free software; you can redistribute it and/or modify | |
10 | * it under the terms of the GNU General Public License as published by | |
11 | * the Free Software Foundation; either version 2 of the License, or | |
12 | * (at your option) any later version. | |
13 | * | |
14 | * This program is distributed in the hope that it will be useful, | |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 | * GNU General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU General Public License | |
20 | * along with this program; see the file COPYING. If not, see | |
21 | * http://www.gnu.org/licenses/. | |
22 | * | |
23 | * This file incorporates work covered by the following copyright and | |
24 | * permission notice: | |
25 | * Copyright (c) 2007-2008 Atheros Communications, Inc. | |
26 | * | |
27 | * Permission to use, copy, modify, and/or distribute this software for any | |
28 | * purpose with or without fee is hereby granted, provided that the above | |
29 | * copyright notice and this permission notice appear in all copies. | |
30 | * | |
31 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
32 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
33 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
34 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
35 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
36 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
37 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
38 | */ | |
39 | ||
a84fab3c CL |
40 | #include <linux/slab.h> |
41 | #include <linux/module.h> | |
42 | #include <linux/etherdevice.h> | |
43 | #include <linux/crc32.h> | |
44 | #include <net/mac80211.h> | |
45 | #include "carl9170.h" | |
46 | #include "hw.h" | |
47 | #include "cmd.h" | |
48 | ||
49 | static void carl9170_dbg_message(struct ar9170 *ar, const char *buf, u32 len) | |
50 | { | |
51 | bool restart = false; | |
52 | enum carl9170_restart_reasons reason = CARL9170_RR_NO_REASON; | |
53 | ||
54 | if (len > 3) { | |
55 | if (memcmp(buf, CARL9170_ERR_MAGIC, 3) == 0) { | |
56 | ar->fw.err_counter++; | |
57 | if (ar->fw.err_counter > 3) { | |
58 | restart = true; | |
59 | reason = CARL9170_RR_TOO_MANY_FIRMWARE_ERRORS; | |
60 | } | |
61 | } | |
62 | ||
63 | if (memcmp(buf, CARL9170_BUG_MAGIC, 3) == 0) { | |
64 | ar->fw.bug_counter++; | |
65 | restart = true; | |
66 | reason = CARL9170_RR_FATAL_FIRMWARE_ERROR; | |
67 | } | |
68 | } | |
69 | ||
70 | wiphy_info(ar->hw->wiphy, "FW: %.*s\n", len, buf); | |
71 | ||
72 | if (restart) | |
73 | carl9170_restart(ar, reason); | |
74 | } | |
75 | ||
76 | static void carl9170_handle_ps(struct ar9170 *ar, struct carl9170_rsp *rsp) | |
77 | { | |
78 | u32 ps; | |
79 | bool new_ps; | |
80 | ||
81 | ps = le32_to_cpu(rsp->psm.state); | |
82 | ||
83 | new_ps = (ps & CARL9170_PSM_COUNTER) != CARL9170_PSM_WAKE; | |
84 | if (ar->ps.state != new_ps) { | |
85 | if (!new_ps) { | |
86 | ar->ps.sleep_ms = jiffies_to_msecs(jiffies - | |
87 | ar->ps.last_action); | |
88 | } | |
89 | ||
90 | ar->ps.last_action = jiffies; | |
91 | ||
92 | ar->ps.state = new_ps; | |
93 | } | |
94 | } | |
95 | ||
96 | static int carl9170_check_sequence(struct ar9170 *ar, unsigned int seq) | |
97 | { | |
98 | if (ar->cmd_seq < -1) | |
99 | return 0; | |
100 | ||
101 | /* | |
102 | * Initialize Counter | |
103 | */ | |
104 | if (ar->cmd_seq < 0) | |
105 | ar->cmd_seq = seq; | |
106 | ||
107 | /* | |
108 | * The sequence is strictly monotonic increasing and it never skips! | |
109 | * | |
110 | * Therefore we can safely assume that whenever we received an | |
111 | * unexpected sequence we have lost some valuable data. | |
112 | */ | |
113 | if (seq != ar->cmd_seq) { | |
114 | int count; | |
115 | ||
116 | count = (seq - ar->cmd_seq) % ar->fw.cmd_bufs; | |
117 | ||
118 | wiphy_err(ar->hw->wiphy, "lost %d command responses/traps! " | |
119 | "w:%d g:%d\n", count, ar->cmd_seq, seq); | |
120 | ||
121 | carl9170_restart(ar, CARL9170_RR_LOST_RSP); | |
122 | return -EIO; | |
123 | } | |
124 | ||
125 | ar->cmd_seq = (ar->cmd_seq + 1) % ar->fw.cmd_bufs; | |
126 | return 0; | |
127 | } | |
128 | ||
129 | static void carl9170_cmd_callback(struct ar9170 *ar, u32 len, void *buffer) | |
130 | { | |
131 | /* | |
132 | * Some commands may have a variable response length | |
133 | * and we cannot predict the correct length in advance. | |
134 | * So we only check if we provided enough space for the data. | |
135 | */ | |
136 | if (unlikely(ar->readlen != (len - 4))) { | |
137 | dev_warn(&ar->udev->dev, "received invalid command response:" | |
138 | "got %d, instead of %d\n", len - 4, ar->readlen); | |
139 | print_hex_dump_bytes("carl9170 cmd:", DUMP_PREFIX_OFFSET, | |
140 | ar->cmd_buf, (ar->cmd.hdr.len + 4) & 0x3f); | |
141 | print_hex_dump_bytes("carl9170 rsp:", DUMP_PREFIX_OFFSET, | |
142 | buffer, len); | |
143 | /* | |
144 | * Do not complete. The command times out, | |
145 | * and we get a stack trace from there. | |
146 | */ | |
147 | carl9170_restart(ar, CARL9170_RR_INVALID_RSP); | |
148 | } | |
149 | ||
150 | spin_lock(&ar->cmd_lock); | |
151 | if (ar->readbuf) { | |
152 | if (len >= 4) | |
153 | memcpy(ar->readbuf, buffer + 4, len - 4); | |
154 | ||
155 | ar->readbuf = NULL; | |
156 | } | |
157 | complete(&ar->cmd_wait); | |
158 | spin_unlock(&ar->cmd_lock); | |
159 | } | |
160 | ||
161 | void carl9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len) | |
162 | { | |
2c208890 | 163 | struct carl9170_rsp *cmd = buf; |
a84fab3c CL |
164 | struct ieee80211_vif *vif; |
165 | ||
a84fab3c CL |
166 | if ((cmd->hdr.cmd & CARL9170_RSP_FLAG) != CARL9170_RSP_FLAG) { |
167 | if (!(cmd->hdr.cmd & CARL9170_CMD_ASYNC_FLAG)) | |
168 | carl9170_cmd_callback(ar, len, buf); | |
169 | ||
170 | return; | |
171 | } | |
172 | ||
173 | if (unlikely(cmd->hdr.len != (len - 4))) { | |
174 | if (net_ratelimit()) { | |
175 | wiphy_err(ar->hw->wiphy, "FW: received over-/under" | |
176 | "sized event %x (%d, but should be %d).\n", | |
177 | cmd->hdr.cmd, cmd->hdr.len, len - 4); | |
178 | ||
179 | print_hex_dump_bytes("dump:", DUMP_PREFIX_NONE, | |
180 | buf, len); | |
181 | } | |
182 | ||
183 | return; | |
184 | } | |
185 | ||
186 | /* hardware event handlers */ | |
187 | switch (cmd->hdr.cmd) { | |
188 | case CARL9170_RSP_PRETBTT: | |
189 | /* pre-TBTT event */ | |
190 | rcu_read_lock(); | |
191 | vif = carl9170_get_main_vif(ar); | |
192 | ||
193 | if (!vif) { | |
194 | rcu_read_unlock(); | |
195 | break; | |
196 | } | |
197 | ||
198 | switch (vif->type) { | |
199 | case NL80211_IFTYPE_STATION: | |
200 | carl9170_handle_ps(ar, cmd); | |
201 | break; | |
202 | ||
203 | case NL80211_IFTYPE_AP: | |
204 | case NL80211_IFTYPE_ADHOC: | |
da93c26d | 205 | case NL80211_IFTYPE_MESH_POINT: |
a84fab3c CL |
206 | carl9170_update_beacon(ar, true); |
207 | break; | |
208 | ||
209 | default: | |
210 | break; | |
211 | } | |
212 | rcu_read_unlock(); | |
213 | ||
214 | break; | |
215 | ||
216 | ||
217 | case CARL9170_RSP_TXCOMP: | |
218 | /* TX status notification */ | |
219 | carl9170_tx_process_status(ar, cmd); | |
220 | break; | |
221 | ||
222 | case CARL9170_RSP_BEACON_CONFIG: | |
223 | /* | |
224 | * (IBSS) beacon send notification | |
225 | * bytes: 04 c2 XX YY B4 B3 B2 B1 | |
226 | * | |
227 | * XX always 80 | |
228 | * YY always 00 | |
229 | * B1-B4 "should" be the number of send out beacons. | |
230 | */ | |
231 | break; | |
232 | ||
233 | case CARL9170_RSP_ATIM: | |
234 | /* End of Atim Window */ | |
235 | break; | |
236 | ||
237 | case CARL9170_RSP_WATCHDOG: | |
238 | /* Watchdog Interrupt */ | |
239 | carl9170_restart(ar, CARL9170_RR_WATCHDOG); | |
240 | break; | |
241 | ||
242 | case CARL9170_RSP_TEXT: | |
243 | /* firmware debug */ | |
244 | carl9170_dbg_message(ar, (char *)buf + 4, len - 4); | |
245 | break; | |
246 | ||
247 | case CARL9170_RSP_HEXDUMP: | |
248 | wiphy_dbg(ar->hw->wiphy, "FW: HD %d\n", len - 4); | |
249 | print_hex_dump_bytes("FW:", DUMP_PREFIX_NONE, | |
250 | (char *)buf + 4, len - 4); | |
251 | break; | |
252 | ||
253 | case CARL9170_RSP_RADAR: | |
254 | if (!net_ratelimit()) | |
255 | break; | |
256 | ||
257 | wiphy_info(ar->hw->wiphy, "FW: RADAR! Please report this " | |
258 | "incident to linux-wireless@vger.kernel.org !\n"); | |
259 | break; | |
260 | ||
261 | case CARL9170_RSP_GPIO: | |
262 | #ifdef CONFIG_CARL9170_WPC | |
263 | if (ar->wps.pbc) { | |
264 | bool state = !!(cmd->gpio.gpio & cpu_to_le32( | |
265 | AR9170_GPIO_PORT_WPS_BUTTON_PRESSED)); | |
266 | ||
267 | if (state != ar->wps.pbc_state) { | |
268 | ar->wps.pbc_state = state; | |
269 | input_report_key(ar->wps.pbc, KEY_WPS_BUTTON, | |
270 | state); | |
271 | input_sync(ar->wps.pbc); | |
272 | } | |
273 | } | |
274 | #endif /* CONFIG_CARL9170_WPC */ | |
275 | break; | |
276 | ||
277 | case CARL9170_RSP_BOOT: | |
278 | complete(&ar->fw_boot_wait); | |
279 | break; | |
280 | ||
281 | default: | |
282 | wiphy_err(ar->hw->wiphy, "FW: received unhandled event %x\n", | |
283 | cmd->hdr.cmd); | |
284 | print_hex_dump_bytes("dump:", DUMP_PREFIX_NONE, buf, len); | |
285 | break; | |
286 | } | |
287 | } | |
288 | ||
289 | static int carl9170_rx_mac_status(struct ar9170 *ar, | |
290 | struct ar9170_rx_head *head, struct ar9170_rx_macstatus *mac, | |
291 | struct ieee80211_rx_status *status) | |
292 | { | |
293 | struct ieee80211_channel *chan; | |
294 | u8 error, decrypt; | |
295 | ||
296 | BUILD_BUG_ON(sizeof(struct ar9170_rx_head) != 12); | |
297 | BUILD_BUG_ON(sizeof(struct ar9170_rx_macstatus) != 4); | |
298 | ||
299 | error = mac->error; | |
300 | ||
301 | if (error & AR9170_RX_ERROR_WRONG_RA) { | |
302 | if (!ar->sniffer_enabled) | |
303 | return -EINVAL; | |
304 | } | |
305 | ||
306 | if (error & AR9170_RX_ERROR_PLCP) { | |
307 | if (!(ar->filter_state & FIF_PLCPFAIL)) | |
308 | return -EINVAL; | |
309 | ||
310 | status->flag |= RX_FLAG_FAILED_PLCP_CRC; | |
311 | } | |
312 | ||
313 | if (error & AR9170_RX_ERROR_FCS) { | |
314 | ar->tx_fcs_errors++; | |
315 | ||
316 | if (!(ar->filter_state & FIF_FCSFAIL)) | |
317 | return -EINVAL; | |
318 | ||
319 | status->flag |= RX_FLAG_FAILED_FCS_CRC; | |
320 | } | |
321 | ||
322 | decrypt = ar9170_get_decrypt_type(mac); | |
323 | if (!(decrypt & AR9170_RX_ENC_SOFTWARE) && | |
324 | decrypt != AR9170_ENC_ALG_NONE) { | |
325 | if ((decrypt == AR9170_ENC_ALG_TKIP) && | |
326 | (error & AR9170_RX_ERROR_MMIC)) | |
327 | status->flag |= RX_FLAG_MMIC_ERROR; | |
328 | ||
329 | status->flag |= RX_FLAG_DECRYPTED; | |
330 | } | |
331 | ||
332 | if (error & AR9170_RX_ERROR_DECRYPT && !ar->sniffer_enabled) | |
333 | return -ENODATA; | |
334 | ||
335 | error &= ~(AR9170_RX_ERROR_MMIC | | |
336 | AR9170_RX_ERROR_FCS | | |
337 | AR9170_RX_ERROR_WRONG_RA | | |
338 | AR9170_RX_ERROR_DECRYPT | | |
339 | AR9170_RX_ERROR_PLCP); | |
340 | ||
341 | /* drop any other error frames */ | |
342 | if (unlikely(error)) { | |
343 | /* TODO: update netdevice's RX dropped/errors statistics */ | |
344 | ||
345 | if (net_ratelimit()) | |
346 | wiphy_dbg(ar->hw->wiphy, "received frame with " | |
347 | "suspicious error code (%#x).\n", error); | |
348 | ||
349 | return -EINVAL; | |
350 | } | |
351 | ||
352 | chan = ar->channel; | |
353 | if (chan) { | |
354 | status->band = chan->band; | |
355 | status->freq = chan->center_freq; | |
356 | } | |
357 | ||
358 | switch (mac->status & AR9170_RX_STATUS_MODULATION) { | |
359 | case AR9170_RX_STATUS_MODULATION_CCK: | |
360 | if (mac->status & AR9170_RX_STATUS_SHORT_PREAMBLE) | |
361 | status->flag |= RX_FLAG_SHORTPRE; | |
362 | switch (head->plcp[0]) { | |
363 | case AR9170_RX_PHY_RATE_CCK_1M: | |
364 | status->rate_idx = 0; | |
365 | break; | |
366 | case AR9170_RX_PHY_RATE_CCK_2M: | |
367 | status->rate_idx = 1; | |
368 | break; | |
369 | case AR9170_RX_PHY_RATE_CCK_5M: | |
370 | status->rate_idx = 2; | |
371 | break; | |
372 | case AR9170_RX_PHY_RATE_CCK_11M: | |
373 | status->rate_idx = 3; | |
374 | break; | |
375 | default: | |
376 | if (net_ratelimit()) { | |
377 | wiphy_err(ar->hw->wiphy, "invalid plcp cck " | |
378 | "rate (%x).\n", head->plcp[0]); | |
379 | } | |
380 | ||
381 | return -EINVAL; | |
382 | } | |
383 | break; | |
384 | ||
385 | case AR9170_RX_STATUS_MODULATION_DUPOFDM: | |
386 | case AR9170_RX_STATUS_MODULATION_OFDM: | |
387 | switch (head->plcp[0] & 0xf) { | |
388 | case AR9170_TXRX_PHY_RATE_OFDM_6M: | |
389 | status->rate_idx = 0; | |
390 | break; | |
391 | case AR9170_TXRX_PHY_RATE_OFDM_9M: | |
392 | status->rate_idx = 1; | |
393 | break; | |
394 | case AR9170_TXRX_PHY_RATE_OFDM_12M: | |
395 | status->rate_idx = 2; | |
396 | break; | |
397 | case AR9170_TXRX_PHY_RATE_OFDM_18M: | |
398 | status->rate_idx = 3; | |
399 | break; | |
400 | case AR9170_TXRX_PHY_RATE_OFDM_24M: | |
401 | status->rate_idx = 4; | |
402 | break; | |
403 | case AR9170_TXRX_PHY_RATE_OFDM_36M: | |
404 | status->rate_idx = 5; | |
405 | break; | |
406 | case AR9170_TXRX_PHY_RATE_OFDM_48M: | |
407 | status->rate_idx = 6; | |
408 | break; | |
409 | case AR9170_TXRX_PHY_RATE_OFDM_54M: | |
410 | status->rate_idx = 7; | |
411 | break; | |
412 | default: | |
413 | if (net_ratelimit()) { | |
414 | wiphy_err(ar->hw->wiphy, "invalid plcp ofdm " | |
415 | "rate (%x).\n", head->plcp[0]); | |
416 | } | |
417 | ||
418 | return -EINVAL; | |
419 | } | |
57fbcce3 | 420 | if (status->band == NL80211_BAND_2GHZ) |
a84fab3c CL |
421 | status->rate_idx += 4; |
422 | break; | |
423 | ||
424 | case AR9170_RX_STATUS_MODULATION_HT: | |
425 | if (head->plcp[3] & 0x80) | |
426 | status->flag |= RX_FLAG_40MHZ; | |
427 | if (head->plcp[6] & 0x80) | |
428 | status->flag |= RX_FLAG_SHORT_GI; | |
429 | ||
430 | status->rate_idx = clamp(0, 75, head->plcp[3] & 0x7f); | |
431 | status->flag |= RX_FLAG_HT; | |
432 | break; | |
433 | ||
434 | default: | |
435 | BUG(); | |
436 | return -ENOSYS; | |
437 | } | |
438 | ||
439 | return 0; | |
440 | } | |
441 | ||
442 | static void carl9170_rx_phy_status(struct ar9170 *ar, | |
443 | struct ar9170_rx_phystatus *phy, struct ieee80211_rx_status *status) | |
444 | { | |
445 | int i; | |
446 | ||
447 | BUILD_BUG_ON(sizeof(struct ar9170_rx_phystatus) != 20); | |
448 | ||
449 | for (i = 0; i < 3; i++) | |
450 | if (phy->rssi[i] != 0x80) | |
451 | status->antenna |= BIT(i); | |
452 | ||
453 | /* post-process RSSI */ | |
454 | for (i = 0; i < 7; i++) | |
455 | if (phy->rssi[i] & 0x80) | |
c452d944 | 456 | phy->rssi[i] = ((~phy->rssi[i] & 0x7f) + 1) & 0x7f; |
a84fab3c CL |
457 | |
458 | /* TODO: we could do something with phy_errors */ | |
459 | status->signal = ar->noise[0] + phy->rssi_combined; | |
460 | } | |
461 | ||
462 | static struct sk_buff *carl9170_rx_copy_data(u8 *buf, int len) | |
463 | { | |
464 | struct sk_buff *skb; | |
465 | int reserved = 0; | |
466 | struct ieee80211_hdr *hdr = (void *) buf; | |
467 | ||
468 | if (ieee80211_is_data_qos(hdr->frame_control)) { | |
469 | u8 *qc = ieee80211_get_qos_ctl(hdr); | |
470 | reserved += NET_IP_ALIGN; | |
471 | ||
04b7dcf9 | 472 | if (*qc & IEEE80211_QOS_CTL_A_MSDU_PRESENT) |
a84fab3c CL |
473 | reserved += NET_IP_ALIGN; |
474 | } | |
475 | ||
476 | if (ieee80211_has_a4(hdr->frame_control)) | |
477 | reserved += NET_IP_ALIGN; | |
478 | ||
479 | reserved = 32 + (reserved & NET_IP_ALIGN); | |
480 | ||
481 | skb = dev_alloc_skb(len + reserved); | |
482 | if (likely(skb)) { | |
483 | skb_reserve(skb, reserved); | |
484 | memcpy(skb_put(skb, len), buf, len); | |
485 | } | |
486 | ||
487 | return skb; | |
488 | } | |
489 | ||
490 | static u8 *carl9170_find_ie(u8 *data, unsigned int len, u8 ie) | |
491 | { | |
492 | struct ieee80211_mgmt *mgmt = (void *)data; | |
493 | u8 *pos, *end; | |
494 | ||
495 | pos = (u8 *)mgmt->u.beacon.variable; | |
496 | end = data + len; | |
497 | while (pos < end) { | |
498 | if (pos + 2 + pos[1] > end) | |
499 | return NULL; | |
500 | ||
501 | if (pos[0] == ie) | |
502 | return pos; | |
503 | ||
504 | pos += 2 + pos[1]; | |
505 | } | |
506 | return NULL; | |
507 | } | |
508 | ||
509 | /* | |
510 | * NOTE: | |
511 | * | |
512 | * The firmware is in charge of waking up the device just before | |
513 | * the AP is expected to transmit the next beacon. | |
514 | * | |
515 | * This leaves the driver with the important task of deciding when | |
516 | * to set the PHY back to bed again. | |
517 | */ | |
518 | static void carl9170_ps_beacon(struct ar9170 *ar, void *data, unsigned int len) | |
519 | { | |
2c208890 | 520 | struct ieee80211_hdr *hdr = data; |
a84fab3c | 521 | struct ieee80211_tim_ie *tim_ie; |
e4e19c03 | 522 | struct ath_common *common = &ar->common; |
a84fab3c CL |
523 | u8 *tim; |
524 | u8 tim_len; | |
525 | bool cam; | |
526 | ||
527 | if (likely(!(ar->hw->conf.flags & IEEE80211_CONF_PS))) | |
528 | return; | |
529 | ||
a84fab3c CL |
530 | /* min. beacon length + FCS_LEN */ |
531 | if (len <= 40 + FCS_LEN) | |
532 | return; | |
533 | ||
e4e19c03 | 534 | /* check if this really is a beacon */ |
a84fab3c | 535 | /* and only beacons from the associated BSSID, please */ |
e4e19c03 | 536 | if (!ath_is_mybeacon(common, hdr) || !common->curaid) |
a84fab3c CL |
537 | return; |
538 | ||
539 | ar->ps.last_beacon = jiffies; | |
540 | ||
541 | tim = carl9170_find_ie(data, len - FCS_LEN, WLAN_EID_TIM); | |
542 | if (!tim) | |
543 | return; | |
544 | ||
545 | if (tim[1] < sizeof(*tim_ie)) | |
546 | return; | |
547 | ||
548 | tim_len = tim[1]; | |
549 | tim_ie = (struct ieee80211_tim_ie *) &tim[2]; | |
550 | ||
551 | if (!WARN_ON_ONCE(!ar->hw->conf.ps_dtim_period)) | |
552 | ar->ps.dtim_counter = (tim_ie->dtim_count - 1) % | |
553 | ar->hw->conf.ps_dtim_period; | |
554 | ||
555 | /* Check whenever the PHY can be turned off again. */ | |
556 | ||
557 | /* 1. What about buffered unicast traffic for our AID? */ | |
558 | cam = ieee80211_check_tim(tim_ie, tim_len, ar->common.curaid); | |
559 | ||
560 | /* 2. Maybe the AP wants to send multicast/broadcast data? */ | |
5820de53 | 561 | cam |= !!(tim_ie->bitmap_ctrl & 0x01); |
a84fab3c CL |
562 | |
563 | if (!cam) { | |
564 | /* back to low-power land. */ | |
565 | ar->ps.off_override &= ~PS_OFF_BCN; | |
566 | carl9170_ps_check(ar); | |
567 | } else { | |
568 | /* force CAM */ | |
569 | ar->ps.off_override |= PS_OFF_BCN; | |
570 | } | |
571 | } | |
572 | ||
c9122c0d CL |
573 | static void carl9170_ba_check(struct ar9170 *ar, void *data, unsigned int len) |
574 | { | |
8986992d | 575 | struct ieee80211_bar *bar = data; |
c9122c0d CL |
576 | struct carl9170_bar_list_entry *entry; |
577 | unsigned int queue; | |
578 | ||
579 | if (likely(!ieee80211_is_back(bar->frame_control))) | |
580 | return; | |
581 | ||
582 | if (len <= sizeof(*bar) + FCS_LEN) | |
583 | return; | |
584 | ||
585 | queue = TID_TO_WME_AC(((le16_to_cpu(bar->control) & | |
586 | IEEE80211_BAR_CTRL_TID_INFO_MASK) >> | |
587 | IEEE80211_BAR_CTRL_TID_INFO_SHIFT) & 7); | |
588 | ||
589 | rcu_read_lock(); | |
590 | list_for_each_entry_rcu(entry, &ar->bar_list[queue], list) { | |
591 | struct sk_buff *entry_skb = entry->skb; | |
592 | struct _carl9170_tx_superframe *super = (void *)entry_skb->data; | |
593 | struct ieee80211_bar *entry_bar = (void *)super->frame_data; | |
594 | ||
595 | #define TID_CHECK(a, b) ( \ | |
596 | ((a) & cpu_to_le16(IEEE80211_BAR_CTRL_TID_INFO_MASK)) == \ | |
597 | ((b) & cpu_to_le16(IEEE80211_BAR_CTRL_TID_INFO_MASK))) \ | |
598 | ||
599 | if (bar->start_seq_num == entry_bar->start_seq_num && | |
600 | TID_CHECK(bar->control, entry_bar->control) && | |
1283ac10 JL |
601 | ether_addr_equal_64bits(bar->ra, entry_bar->ta) && |
602 | ether_addr_equal_64bits(bar->ta, entry_bar->ra)) { | |
c9122c0d CL |
603 | struct ieee80211_tx_info *tx_info; |
604 | ||
605 | tx_info = IEEE80211_SKB_CB(entry_skb); | |
606 | tx_info->flags |= IEEE80211_TX_STAT_ACK; | |
607 | ||
608 | spin_lock_bh(&ar->bar_list_lock[queue]); | |
609 | list_del_rcu(&entry->list); | |
610 | spin_unlock_bh(&ar->bar_list_lock[queue]); | |
611 | kfree_rcu(entry, head); | |
612 | break; | |
613 | } | |
614 | } | |
615 | rcu_read_unlock(); | |
616 | ||
617 | #undef TID_CHECK | |
618 | } | |
619 | ||
33dd7699 CL |
620 | static bool carl9170_ampdu_check(struct ar9170 *ar, u8 *buf, u8 ms, |
621 | struct ieee80211_rx_status *rx_status) | |
8f236d1b CL |
622 | { |
623 | __le16 fc; | |
624 | ||
625 | if ((ms & AR9170_RX_STATUS_MPDU) == AR9170_RX_STATUS_MPDU_SINGLE) { | |
626 | /* | |
627 | * This frame is not part of an aMPDU. | |
628 | * Therefore it is not subjected to any | |
629 | * of the following content restrictions. | |
630 | */ | |
631 | return true; | |
632 | } | |
633 | ||
33dd7699 CL |
634 | rx_status->flag |= RX_FLAG_AMPDU_DETAILS | RX_FLAG_AMPDU_LAST_KNOWN; |
635 | rx_status->ampdu_reference = ar->ampdu_ref; | |
636 | ||
8f236d1b CL |
637 | /* |
638 | * "802.11n - 7.4a.3 A-MPDU contents" describes in which contexts | |
639 | * certain frame types can be part of an aMPDU. | |
640 | * | |
641 | * In order to keep the processing cost down, I opted for a | |
642 | * stateless filter solely based on the frame control field. | |
643 | */ | |
644 | ||
645 | fc = ((struct ieee80211_hdr *)buf)->frame_control; | |
646 | if (ieee80211_is_data_qos(fc) && ieee80211_is_data_present(fc)) | |
647 | return true; | |
648 | ||
649 | if (ieee80211_is_ack(fc) || ieee80211_is_back(fc) || | |
650 | ieee80211_is_back_req(fc)) | |
651 | return true; | |
652 | ||
653 | if (ieee80211_is_action(fc)) | |
654 | return true; | |
655 | ||
656 | return false; | |
657 | } | |
658 | ||
6c4a5f24 CL |
659 | static int carl9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len, |
660 | struct ieee80211_rx_status *status) | |
661 | { | |
662 | struct sk_buff *skb; | |
663 | ||
664 | /* (driver) frame trap handler | |
665 | * | |
666 | * Because power-saving mode handing has to be implemented by | |
667 | * the driver/firmware. We have to check each incoming beacon | |
668 | * from the associated AP, if there's new data for us (either | |
669 | * broadcast/multicast or unicast) we have to react quickly. | |
670 | * | |
671 | * So, if you have you want to add additional frame trap | |
672 | * handlers, this would be the perfect place! | |
673 | */ | |
674 | ||
675 | carl9170_ps_beacon(ar, buf, len); | |
676 | ||
677 | carl9170_ba_check(ar, buf, len); | |
678 | ||
679 | skb = carl9170_rx_copy_data(buf, len); | |
680 | if (!skb) | |
681 | return -ENOMEM; | |
682 | ||
fc5e286f | 683 | memcpy(IEEE80211_SKB_RXCB(skb), status, sizeof(*status)); |
6c4a5f24 CL |
684 | ieee80211_rx(ar->hw, skb); |
685 | return 0; | |
686 | } | |
687 | ||
a84fab3c CL |
688 | /* |
689 | * If the frame alignment is right (or the kernel has | |
690 | * CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS), and there | |
691 | * is only a single MPDU in the USB frame, then we could | |
692 | * submit to mac80211 the SKB directly. However, since | |
693 | * there may be multiple packets in one SKB in stream | |
694 | * mode, and we need to observe the proper ordering, | |
695 | * this is non-trivial. | |
696 | */ | |
6c4a5f24 | 697 | static void carl9170_rx_untie_data(struct ar9170 *ar, u8 *buf, int len) |
a84fab3c CL |
698 | { |
699 | struct ar9170_rx_head *head; | |
700 | struct ar9170_rx_macstatus *mac; | |
701 | struct ar9170_rx_phystatus *phy = NULL; | |
702 | struct ieee80211_rx_status status; | |
a84fab3c | 703 | int mpdu_len; |
8f236d1b | 704 | u8 mac_status; |
a84fab3c CL |
705 | |
706 | if (!IS_STARTED(ar)) | |
707 | return; | |
708 | ||
c8a16c68 CL |
709 | if (unlikely(len < sizeof(*mac))) |
710 | goto drop; | |
a84fab3c | 711 | |
33dd7699 CL |
712 | memset(&status, 0, sizeof(status)); |
713 | ||
a84fab3c CL |
714 | mpdu_len = len - sizeof(*mac); |
715 | ||
716 | mac = (void *)(buf + mpdu_len); | |
8f236d1b CL |
717 | mac_status = mac->status; |
718 | switch (mac_status & AR9170_RX_STATUS_MPDU) { | |
a84fab3c | 719 | case AR9170_RX_STATUS_MPDU_FIRST: |
33dd7699 | 720 | ar->ampdu_ref++; |
a84fab3c CL |
721 | /* Aggregated MPDUs start with an PLCP header */ |
722 | if (likely(mpdu_len >= sizeof(struct ar9170_rx_head))) { | |
723 | head = (void *) buf; | |
724 | ||
725 | /* | |
726 | * The PLCP header needs to be cached for the | |
727 | * following MIDDLE + LAST A-MPDU packets. | |
728 | * | |
729 | * So, if you are wondering why all frames seem | |
730 | * to share a common RX status information, | |
731 | * then you have the answer right here... | |
732 | */ | |
733 | memcpy(&ar->rx_plcp, (void *) buf, | |
734 | sizeof(struct ar9170_rx_head)); | |
735 | ||
736 | mpdu_len -= sizeof(struct ar9170_rx_head); | |
737 | buf += sizeof(struct ar9170_rx_head); | |
738 | ||
739 | ar->rx_has_plcp = true; | |
740 | } else { | |
741 | if (net_ratelimit()) { | |
742 | wiphy_err(ar->hw->wiphy, "plcp info " | |
743 | "is clipped.\n"); | |
744 | } | |
745 | ||
c8a16c68 | 746 | goto drop; |
a84fab3c CL |
747 | } |
748 | break; | |
749 | ||
750 | case AR9170_RX_STATUS_MPDU_LAST: | |
33dd7699 CL |
751 | status.flag |= RX_FLAG_AMPDU_IS_LAST; |
752 | ||
a84fab3c CL |
753 | /* |
754 | * The last frame of an A-MPDU has an extra tail | |
755 | * which does contain the phy status of the whole | |
756 | * aggregate. | |
757 | */ | |
a84fab3c CL |
758 | if (likely(mpdu_len >= sizeof(struct ar9170_rx_phystatus))) { |
759 | mpdu_len -= sizeof(struct ar9170_rx_phystatus); | |
760 | phy = (void *)(buf + mpdu_len); | |
761 | } else { | |
762 | if (net_ratelimit()) { | |
763 | wiphy_err(ar->hw->wiphy, "frame tail " | |
764 | "is clipped.\n"); | |
765 | } | |
766 | ||
c8a16c68 | 767 | goto drop; |
a84fab3c CL |
768 | } |
769 | ||
770 | case AR9170_RX_STATUS_MPDU_MIDDLE: | |
771 | /* These are just data + mac status */ | |
772 | if (unlikely(!ar->rx_has_plcp)) { | |
773 | if (!net_ratelimit()) | |
774 | return; | |
775 | ||
776 | wiphy_err(ar->hw->wiphy, "rx stream does not start " | |
777 | "with a first_mpdu frame tag.\n"); | |
778 | ||
c8a16c68 | 779 | goto drop; |
a84fab3c CL |
780 | } |
781 | ||
782 | head = &ar->rx_plcp; | |
783 | break; | |
784 | ||
785 | case AR9170_RX_STATUS_MPDU_SINGLE: | |
786 | /* single mpdu has both: plcp (head) and phy status (tail) */ | |
787 | head = (void *) buf; | |
788 | ||
789 | mpdu_len -= sizeof(struct ar9170_rx_head); | |
790 | mpdu_len -= sizeof(struct ar9170_rx_phystatus); | |
791 | ||
792 | buf += sizeof(struct ar9170_rx_head); | |
793 | phy = (void *)(buf + mpdu_len); | |
794 | break; | |
795 | ||
796 | default: | |
797 | BUG_ON(1); | |
798 | break; | |
799 | } | |
800 | ||
801 | /* FC + DU + RA + FCS */ | |
c8a16c68 CL |
802 | if (unlikely(mpdu_len < (2 + 2 + ETH_ALEN + FCS_LEN))) |
803 | goto drop; | |
a84fab3c | 804 | |
c8a16c68 CL |
805 | if (unlikely(carl9170_rx_mac_status(ar, head, mac, &status))) |
806 | goto drop; | |
a84fab3c | 807 | |
33dd7699 | 808 | if (!carl9170_ampdu_check(ar, buf, mac_status, &status)) |
8f236d1b CL |
809 | goto drop; |
810 | ||
a84fab3c CL |
811 | if (phy) |
812 | carl9170_rx_phy_status(ar, phy, &status); | |
649a6ac4 CL |
813 | else |
814 | status.flag |= RX_FLAG_NO_SIGNAL_VAL; | |
a84fab3c | 815 | |
6c4a5f24 | 816 | if (carl9170_handle_mpdu(ar, buf, mpdu_len, &status)) |
c8a16c68 CL |
817 | goto drop; |
818 | ||
c8a16c68 | 819 | return; |
c8a16c68 CL |
820 | drop: |
821 | ar->rx_dropped++; | |
a84fab3c CL |
822 | } |
823 | ||
824 | static void carl9170_rx_untie_cmds(struct ar9170 *ar, const u8 *respbuf, | |
825 | const unsigned int resplen) | |
826 | { | |
827 | struct carl9170_rsp *cmd; | |
828 | int i = 0; | |
829 | ||
830 | while (i < resplen) { | |
831 | cmd = (void *) &respbuf[i]; | |
832 | ||
833 | i += cmd->hdr.len + 4; | |
834 | if (unlikely(i > resplen)) | |
835 | break; | |
836 | ||
b4764c80 CL |
837 | if (carl9170_check_sequence(ar, cmd->hdr.seq)) |
838 | break; | |
839 | ||
a84fab3c CL |
840 | carl9170_handle_command_response(ar, cmd, cmd->hdr.len + 4); |
841 | } | |
842 | ||
843 | if (unlikely(i != resplen)) { | |
844 | if (!net_ratelimit()) | |
845 | return; | |
846 | ||
847 | wiphy_err(ar->hw->wiphy, "malformed firmware trap:\n"); | |
848 | print_hex_dump_bytes("rxcmd:", DUMP_PREFIX_OFFSET, | |
849 | respbuf, resplen); | |
850 | } | |
851 | } | |
852 | ||
853 | static void __carl9170_rx(struct ar9170 *ar, u8 *buf, unsigned int len) | |
854 | { | |
855 | unsigned int i = 0; | |
856 | ||
857 | /* weird thing, but this is the same in the original driver */ | |
858 | while (len > 2 && i < 12 && buf[0] == 0xff && buf[1] == 0xff) { | |
859 | i += 2; | |
860 | len -= 2; | |
861 | buf += 2; | |
862 | } | |
863 | ||
864 | if (unlikely(len < 4)) | |
865 | return; | |
866 | ||
867 | /* found the 6 * 0xffff marker? */ | |
868 | if (i == 12) | |
869 | carl9170_rx_untie_cmds(ar, buf, len); | |
870 | else | |
6c4a5f24 | 871 | carl9170_rx_untie_data(ar, buf, len); |
a84fab3c CL |
872 | } |
873 | ||
874 | static void carl9170_rx_stream(struct ar9170 *ar, void *buf, unsigned int len) | |
875 | { | |
876 | unsigned int tlen, wlen = 0, clen = 0; | |
877 | struct ar9170_stream *rx_stream; | |
878 | u8 *tbuf; | |
879 | ||
880 | tbuf = buf; | |
881 | tlen = len; | |
882 | ||
883 | while (tlen >= 4) { | |
884 | rx_stream = (void *) tbuf; | |
885 | clen = le16_to_cpu(rx_stream->length); | |
886 | wlen = ALIGN(clen, 4); | |
887 | ||
888 | /* check if this is stream has a valid tag.*/ | |
889 | if (rx_stream->tag != cpu_to_le16(AR9170_RX_STREAM_TAG)) { | |
890 | /* | |
891 | * TODO: handle the highly unlikely event that the | |
892 | * corrupted stream has the TAG at the right position. | |
893 | */ | |
894 | ||
895 | /* check if the frame can be repaired. */ | |
896 | if (!ar->rx_failover_missing) { | |
897 | ||
898 | /* this is not "short read". */ | |
899 | if (net_ratelimit()) { | |
900 | wiphy_err(ar->hw->wiphy, | |
901 | "missing tag!\n"); | |
902 | } | |
903 | ||
904 | __carl9170_rx(ar, tbuf, tlen); | |
905 | return; | |
906 | } | |
907 | ||
908 | if (ar->rx_failover_missing > tlen) { | |
909 | if (net_ratelimit()) { | |
910 | wiphy_err(ar->hw->wiphy, | |
911 | "possible multi " | |
912 | "stream corruption!\n"); | |
913 | goto err_telluser; | |
914 | } else { | |
915 | goto err_silent; | |
916 | } | |
917 | } | |
918 | ||
919 | memcpy(skb_put(ar->rx_failover, tlen), tbuf, tlen); | |
920 | ar->rx_failover_missing -= tlen; | |
921 | ||
922 | if (ar->rx_failover_missing <= 0) { | |
923 | /* | |
924 | * nested carl9170_rx_stream call! | |
925 | * | |
25985edc | 926 | * termination is guaranteed, even when the |
a84fab3c CL |
927 | * combined frame also have an element with |
928 | * a bad tag. | |
929 | */ | |
930 | ||
931 | ar->rx_failover_missing = 0; | |
932 | carl9170_rx_stream(ar, ar->rx_failover->data, | |
933 | ar->rx_failover->len); | |
934 | ||
935 | skb_reset_tail_pointer(ar->rx_failover); | |
936 | skb_trim(ar->rx_failover, 0); | |
937 | } | |
938 | ||
939 | return; | |
940 | } | |
941 | ||
942 | /* check if stream is clipped */ | |
943 | if (wlen > tlen - 4) { | |
944 | if (ar->rx_failover_missing) { | |
945 | /* TODO: handle double stream corruption. */ | |
946 | if (net_ratelimit()) { | |
947 | wiphy_err(ar->hw->wiphy, "double rx " | |
948 | "stream corruption!\n"); | |
949 | goto err_telluser; | |
950 | } else { | |
951 | goto err_silent; | |
952 | } | |
953 | } | |
954 | ||
955 | /* | |
956 | * save incomplete data set. | |
957 | * the firmware will resend the missing bits when | |
958 | * the rx - descriptor comes round again. | |
959 | */ | |
960 | ||
961 | memcpy(skb_put(ar->rx_failover, tlen), tbuf, tlen); | |
962 | ar->rx_failover_missing = clen - tlen; | |
963 | return; | |
964 | } | |
965 | __carl9170_rx(ar, rx_stream->payload, clen); | |
966 | ||
967 | tbuf += wlen + 4; | |
968 | tlen -= wlen + 4; | |
969 | } | |
970 | ||
971 | if (tlen) { | |
972 | if (net_ratelimit()) { | |
973 | wiphy_err(ar->hw->wiphy, "%d bytes of unprocessed " | |
974 | "data left in rx stream!\n", tlen); | |
975 | } | |
976 | ||
977 | goto err_telluser; | |
978 | } | |
979 | ||
980 | return; | |
981 | ||
982 | err_telluser: | |
983 | wiphy_err(ar->hw->wiphy, "damaged RX stream data [want:%d, " | |
984 | "data:%d, rx:%d, pending:%d ]\n", clen, wlen, tlen, | |
985 | ar->rx_failover_missing); | |
986 | ||
987 | if (ar->rx_failover_missing) | |
988 | print_hex_dump_bytes("rxbuf:", DUMP_PREFIX_OFFSET, | |
989 | ar->rx_failover->data, | |
990 | ar->rx_failover->len); | |
991 | ||
992 | print_hex_dump_bytes("stream:", DUMP_PREFIX_OFFSET, | |
993 | buf, len); | |
994 | ||
995 | wiphy_err(ar->hw->wiphy, "please check your hardware and cables, if " | |
996 | "you see this message frequently.\n"); | |
997 | ||
998 | err_silent: | |
999 | if (ar->rx_failover_missing) { | |
1000 | skb_reset_tail_pointer(ar->rx_failover); | |
1001 | skb_trim(ar->rx_failover, 0); | |
1002 | ar->rx_failover_missing = 0; | |
1003 | } | |
1004 | } | |
1005 | ||
1006 | void carl9170_rx(struct ar9170 *ar, void *buf, unsigned int len) | |
1007 | { | |
1008 | if (ar->fw.rx_stream) | |
1009 | carl9170_rx_stream(ar, buf, len); | |
1010 | else | |
1011 | __carl9170_rx(ar, buf, len); | |
1012 | } |